diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 31316503d..23901558b 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -341,6 +341,15 @@ pub struct ExportConfig { pub renaming_overrides_prefixing: bool, /// Mangling configuration. pub mangle: MangleConfig, + /// Whether to instantiate the monomorphs of template types used as function return values. This + /// is needed for C compatibility, because otherwise compilers warn (`-Wreturn-type-c-linkage` + /// on gcc/clang) or even reject (MSVC) those function definitions. The compensation is made by + /// emitting a single struct with one field for each monomorphized type. The emitted wrapper + /// struct's name can optionally be overridden by [`return_value_monomorphs_struct_name`]. + pub instantiate_return_value_monomorphs: bool, + /// Overrides the struct name to use when [`instantiate_return_value_monomorphs`] is enabled + /// (ignored otherwise). If not specified, the default is `__cbindgen_return_value_monomorphs`. + pub return_value_monomorphs_struct_name: Option, } /// Mangling-specific configuration. diff --git a/src/bindgen/ir/cfg.rs b/src/bindgen/ir/cfg.rs index 65de1a2ff..83ea284f3 100644 --- a/src/bindgen/ir/cfg.rs +++ b/src/bindgen/ir/cfg.rs @@ -42,7 +42,7 @@ impl<'a> DefineKey<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum Cfg { Boolean(String), Named(String, String), @@ -129,10 +129,10 @@ impl syn::parse::Parse for Cfg { impl Cfg { pub fn join(cfgs: &[Cfg]) -> Option { - if cfgs.is_empty() { - None - } else { - Some(Cfg::All(cfgs.to_owned())) + match cfgs { + [] => None, + [cfg] => Some(cfg.clone()), + _ => Some(Cfg::All(cfgs.to_owned())), } } diff --git a/src/bindgen/ir/documentation.rs b/src/bindgen/ir/documentation.rs index e6dba9794..b162524af 100644 --- a/src/bindgen/ir/documentation.rs +++ b/src/bindgen/ir/documentation.rs @@ -4,7 +4,7 @@ use crate::bindgen::utilities::SynAttributeHelpers; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Documentation { pub doc_comment: Vec, } @@ -27,8 +27,6 @@ impl Documentation { } pub fn none() -> Self { - Documentation { - doc_comment: Vec::new(), - } + Self::default() } } diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 2e633a7df..f7a58ac5b 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -17,7 +17,7 @@ use crate::bindgen::ir::{ use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::writer::{ListType, SourceWriter}; @@ -317,6 +317,16 @@ impl Enum { repr.style != ReprStyle::C } + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for v in &self.variants { + if let VariantBody::Body { ref body, .. } = v.body { + body.find_return_value_monomorphs(m); + } + } + }); + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { if self.is_generic() { return; diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 79adfce94..de91f6e2d 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -9,9 +9,11 @@ use syn::ext::IdentExt; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, GenericPath, Path, Type}; +use crate::bindgen::ir::{ + AnnotationSet, Cfg, Documentation, GenericParams, GenericPath, Path, Type, +}; use crate::bindgen::library::Library; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::utilities::IterHelpers; @@ -47,6 +49,11 @@ impl Function { attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { + let GenericParams(generics) = GenericParams::load(&sig.generics)?; + if !generics.is_empty() { + return Err("Generic functions are not supported".to_owned()); + } + let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?; if sig.variadic.is_some() { args.push(FunctionArgument { @@ -129,6 +136,11 @@ impl Function { } } + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + m.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty)); + }); + } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { self.ret.add_monomorphs(library, out); for arg in &self.args { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 9b33a15c7..d6fa7a685 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -15,7 +15,7 @@ use crate::bindgen::ir::{ }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::utilities::IterHelpers; @@ -168,10 +168,17 @@ impl Struct { /// Attempts to convert this struct to a typedef (only works for transparent structs). pub fn as_typedef(&self) -> Option { - match self.fields.first() { - Some(field) if self.is_transparent => Some(Typedef::new_from_struct_field(self, field)), - _ => None, - } + let field = self.fields.first()?; + self.is_transparent + .then(|| Typedef::new_from_struct_field(self, field)) + } + + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for field in &self.fields { + field.ty.find_return_value_monomorphs(m, false); + } + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 4a41d4cf3..71db2efe2 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path}; use crate::bindgen::library::Library; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -739,6 +739,22 @@ impl Type { self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out) } + pub fn find_return_value_monomorphs( + &self, + monomorphs: &mut ReturnValueMonomorphs<'_>, + is_return_value: bool, + ) { + match self { + Type::Ptr { ty, .. } => ty.find_return_value_monomorphs(monomorphs, false), + Type::Path(generic) => monomorphs.handle_return_value_path(generic, is_return_value), + Type::Primitive(_) => {} + Type::Array(ty, _) => ty.find_return_value_monomorphs(monomorphs, false), + Type::FuncPtr { ret, args, .. } => { + monomorphs.handle_function(ret, args.iter().map(|(_, arg)| arg)) + } + } + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { match *self { Type::Ptr { ref ty, .. } => { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e775a4e80..9c030441e 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -15,7 +15,7 @@ use crate::bindgen::ir::{ }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; /// A type alias that is represented as a C typedef #[derive(Debug, Clone)] @@ -102,6 +102,17 @@ impl Typedef { } } + pub fn find_return_value_monomorphs( + &self, + monomorphs: &mut ReturnValueMonomorphs<'_>, + is_return_value: bool, + ) { + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + self.aliased + .find_return_value_monomorphs(m, is_return_value); + }); + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 410e21a27..9779afbf1 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -13,7 +13,7 @@ use crate::bindgen::ir::{ }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::utilities::IterHelpers; @@ -100,6 +100,14 @@ impl Union { } } + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for field in &self.fields { + field.ty.find_return_value_monomorphs(m, false); + } + }); + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic unions can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f9..f4bd0375f 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -10,9 +10,11 @@ use crate::bindgen::config::{Config, Language, SortKey}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; 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::ir::{ + Constant, Enum, Function, Item, ItemContainer, ItemMap, OpaqueItem, Path, Static, Struct, + Typedef, Union, +}; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -81,6 +83,12 @@ impl Library { let mut dependencies = Dependencies::new(); + if self.config.language == Language::Cxx + && self.config.export.instantiate_return_value_monomorphs + { + self.instantiate_return_value_monomorphs(&mut dependencies); + } + for function in &self.functions { function.add_dependencies(&self, &mut dependencies); } @@ -447,4 +455,28 @@ impl Library { x.mangle_paths(&monomorphs); } } + + fn instantiate_return_value_monomorphs(&mut self, dependencies: &mut Dependencies) { + let mut monomorphs = ReturnValueMonomorphs::new(self); + self.structs + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); + self.unions + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); + self.enums + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); + self.typedefs + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs, false)); + for x in &self.functions { + x.find_return_value_monomorphs(&mut monomorphs); + } + + let struct_name = match self.config.export.return_value_monomorphs_struct_name { + Some(ref name) => name, + _ => "__cbindgen_return_value_monomorphs", + }; + if let Some((struct_name, struct_def)) = monomorphs.into_struct(struct_name) { + self.structs.try_insert(struct_def); + struct_name.add_dependencies(self, dependencies); + } + } } diff --git a/src/bindgen/monomorph.rs b/src/bindgen/monomorph.rs index 2dab9cf46..6c8584556 100644 --- a/src/bindgen/monomorph.rs +++ b/src/bindgen/monomorph.rs @@ -2,11 +2,13 @@ * 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::HashMap; +use std::collections::{HashMap, HashSet}; +use std::iter::FromIterator as _; use std::mem; use crate::bindgen::ir::{ - Enum, GenericArgument, GenericPath, Item, OpaqueItem, Path, Struct, Typedef, Union, + Cfg, Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem, + Path, Struct, Type, Typedef, Union, }; use crate::bindgen::library::Library; @@ -145,3 +147,133 @@ impl Monomorphs { mem::take(&mut self.enums) } } + +/// A helper for collecting all function return value momomorphs -- template types returned by +/// functions that can lead to compilation warnings/errors if not explicitly instantiated. +pub struct ReturnValueMonomorphs<'a> { + library: &'a Library, + monomorphs: HashSet<(GenericPath, Option)>, + active_cfgs: Vec, +} + +impl<'a> ReturnValueMonomorphs<'a> { + pub fn new(library: &'a Library) -> Self { + Self { + library, + monomorphs: HashSet::new(), + active_cfgs: Vec::new(), + } + } + + fn insert(&mut self, generic: &GenericPath, cfg: Option) { + if !generic.generics().is_empty() { + self.with_active_cfg(cfg, |m| { + let cfg = Cfg::join(&m.active_cfgs); + m.monomorphs.insert((generic.clone(), cfg)); + }); + } + } + + pub fn with_active_cfg(&mut self, cfg: Option, thunk: impl FnOnce(&mut Self)) { + if let Some(cfg) = cfg { + self.active_cfgs.push(cfg); + thunk(self); + self.active_cfgs.pop(); + } else { + thunk(self); + } + } + + /// Resolve a typedef that is a function return value, specializing it first if needed. + fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) { + self.with_active_cfg(typedef.cfg.clone(), |m| { + if typedef.is_generic() { + let args = generic.generics(); + let aliased = &typedef.aliased; + let mappings = typedef.generic_params.call(typedef.path.name(), args); + let aliased = aliased.specialize(&mappings); + aliased.find_return_value_monomorphs(m, true); + } else { + typedef.find_return_value_monomorphs(m, true); + } + }); + } + + /// Once we find a function return type, what we do with it depends on the type of item it + /// resolves to. Typedefs need to be resolved recursively, while generic structs, unions, and + /// enums are captured in the set of return value monomorphs. + pub fn handle_return_value_path(&mut self, generic: &GenericPath, is_return_value: bool) { + if !is_return_value { + return; + } + + for item in self.library.get_items(generic.path()).into_iter().flatten() { + match item { + // Constants and statics cannot be function return types + ItemContainer::Constant(_) | ItemContainer::Static(_) => {} + // Opaque items cannot be instantiated (doomed to compilation failure) + ItemContainer::OpaqueItem(_) => {} + ItemContainer::Typedef(t) => self.handle_return_value_typedef(t, generic), + ItemContainer::Union(u) => self.insert(generic, u.cfg), + ItemContainer::Enum(e) => self.insert(generic, e.cfg), + ItemContainer::Struct(s) => { + if let Some(t) = s.as_typedef() { + self.handle_return_value_typedef(t, generic); + } else { + self.insert(generic, s.cfg); + } + } + } + } + } + + /// Whenever we encounter a function (or function pointer), we need to check whether its return + /// value is an instantiated generic type (monomorph). + pub fn handle_function<'i>(&mut self, ret: &Type, args: impl IntoIterator) { + ret.find_return_value_monomorphs(self, true); + for arg in args.into_iter() { + arg.find_return_value_monomorphs(self, false); + } + } + + /// Emit all instantiated return value monomorphs as fields of a dummy struct, which silences + /// warnings and errors on several compilers. + pub fn into_struct(self, struct_name: &str) -> Option<(Type, Struct)> { + if self.monomorphs.is_empty() { + return None; + } + + // Sort the output so that the struct remains stable across runs (tests want that). + let mut monomorphs = Vec::from_iter(self.monomorphs); + monomorphs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2)); + let fields = monomorphs + .into_iter() + .enumerate() + .map(|(i, (path, cfg))| { + let mut f = Field::from_name_and_type(format!("field{}", i), Type::Path(path)); + f.cfg = cfg; + f + }) + .collect(); + let doc_comment = vec![ + " Dummy struct emitted by cbindgen to avoid compiler warnings/errors about", + " return type C linkage for template types returned by value from functions", + ]; + let doc_comment = doc_comment.into_iter().map(Into::into).collect(); + let struct_name = GenericPath::new(Path::new(struct_name), vec![]); + let struct_def = Struct::new( + struct_name.path().clone(), + Default::default(), // no generic params + fields, + false, // no tag field + false, // not an enum body + None, // no special alignment requirements + false, // not transparent + None, // no conf + Default::default(), // no annotations + Documentation { doc_comment }, + ); + let struct_name = Type::Path(struct_name); + Some((struct_name, struct_def)) + } +} diff --git a/tests/expectations/const_generics_char.cpp b/tests/expectations/const_generics_char.cpp index 7c5108cfa..4c87fdadd 100644 --- a/tests/expectations/const_generics_char.cpp +++ b/tests/expectations/const_generics_char.cpp @@ -11,6 +11,12 @@ struct TakeUntil { uintptr_t point; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + TakeUntil<0> field0; +}; + extern "C" { TakeUntil<0> until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_thru.cpp b/tests/expectations/const_generics_thru.cpp index de646d975..00fe28bd6 100644 --- a/tests/expectations/const_generics_thru.cpp +++ b/tests/expectations/const_generics_thru.cpp @@ -14,6 +14,13 @@ struct Outer { Inner inner; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + Outer<1> field0; + Outer<2> field1; +}; + extern "C" { Outer<1> one(); diff --git a/tests/expectations/must_use.cpp b/tests/expectations/must_use.cpp index 45333eb4d..35c30c918 100644 --- a/tests/expectations/must_use.cpp +++ b/tests/expectations/must_use.cpp @@ -26,6 +26,12 @@ struct MUST_USE_STRUCT MaybeOwnedPtr { }; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + MaybeOwnedPtr field0; +}; + template struct MUST_USE_STRUCT OwnedPtr { T *ptr; diff --git a/tests/expectations/return_value_monomorphs.c b/tests/expectations/return_value_monomorphs.c new file mode 100644 index 000000000..e6fe3b9c0 --- /dev/null +++ b/tests/expectations/return_value_monomorphs.c @@ -0,0 +1,121 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +typedef struct { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef Foo_u16 FooConditional_u16; +#endif + +typedef struct { + int16_t x; +} Foo_i16; + +typedef struct { + int8_t x; +} Foo_i8; + +typedef struct { + int32_t x; +} NotReturnValue_i32; + +typedef struct { + Foo_i8 (*f)(void); + void (*g)(NotReturnValue_i32); +} FooField; + +typedef struct { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef Bar_i8__i32 IntBar_i32; + +typedef struct { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct { + int32_t x; +} Foo_i32; + +typedef Foo_i32 WrapFoo_i32; + +typedef struct { + bool p; + bool q; +} Bar_bool__bool; + +typedef Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct { + int64_t x; +} Foo_i64; + +typedef Foo_i64 Transparent; + +typedef struct { + uint8_t x; +} Foo_u8; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +Foo_i16 fnE(void); + +void fnF(FooField f); + +Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +Foo_u8 fnO(void); +#endif + +Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs.compat.c b/tests/expectations/return_value_monomorphs.compat.c new file mode 100644 index 000000000..96687ec84 --- /dev/null +++ b/tests/expectations/return_value_monomorphs.compat.c @@ -0,0 +1,129 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +typedef struct { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef Foo_u16 FooConditional_u16; +#endif + +typedef struct { + int16_t x; +} Foo_i16; + +typedef struct { + int8_t x; +} Foo_i8; + +typedef struct { + int32_t x; +} NotReturnValue_i32; + +typedef struct { + Foo_i8 (*f)(void); + void (*g)(NotReturnValue_i32); +} FooField; + +typedef struct { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef Bar_i8__i32 IntBar_i32; + +typedef struct { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct { + int32_t x; +} Foo_i32; + +typedef Foo_i32 WrapFoo_i32; + +typedef struct { + bool p; + bool q; +} Bar_bool__bool; + +typedef Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct { + int64_t x; +} Foo_i64; + +typedef Foo_i64 Transparent; + +typedef struct { + uint8_t x; +} Foo_u8; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +Foo_i16 fnE(void); + +void fnF(FooField f); + +Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +Foo_u8 fnO(void); +#endif + +Foo_u8 fnP(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs.cpp b/tests/expectations/return_value_monomorphs.cpp new file mode 100644 index 000000000..0bf7a1aa2 --- /dev/null +++ b/tests/expectations/return_value_monomorphs.cpp @@ -0,0 +1,114 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include +#include + +template +struct Bar { + P p; + Q q; +}; + +template +struct Foo { + T x; +}; + +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + Bar field0; + Bar field1; + Bar field2; + Bar field3; + Foo field4; +#if defined(DEFINE_FEATURE_1) + Foo field5 +#endif + ; + Foo field6; +#if (defined(DEFINE_FEATURE_2) && defined(DEFINE_FEATURE_1)) + Foo field7 +#endif + ; + Foo field8; + Foo field9; + Foo field10; + Foo field11; +}; + +#if defined(DEFINE_FEATURE_1) +template +using FooConditional = Foo; +#endif + +template +struct NotReturnValue { + T x; +}; + +struct FooField { + Foo (*f)(); + void (*g)(NotReturnValue); +}; + +template +using IntBar = Bar; + +using IntBoolBar = IntBar; + +template +using WrapFoo = Foo; + +using BoolBoolBar = Bar; + +using WrapBoolBoolBar = BoolBoolBar; + +using WrapNonZeroInt = int8_t; + +using Transparent = Foo; + +extern "C" { + +#if defined(DEFINE_FEATURE_2) +FooConditional double_feature(); +#endif + +int32_t fnA(); + +int16_t fnB(); + +Foo fnE(); + +void fnF(FooField f); + +Bar fnG(); + +IntBar fnH(); + +IntBoolBar fnI(); + +WrapFoo fnJ(); + +WrapBoolBoolBar fnK(); + +Foo fnL(); + +WrapNonZeroInt fnM(); + +Transparent fnN(); + +#if defined(DEFINE_FEATURE_1) +Foo fnO(); +#endif + +Foo fnP(); + +} // extern "C" diff --git a/tests/expectations/return_value_monomorphs.pyx b/tests/expectations/return_value_monomorphs.pyx new file mode 100644 index 000000000..09cb8ce96 --- /dev/null +++ b/tests/expectations/return_value_monomorphs.pyx @@ -0,0 +1,108 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +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 *: + + ctypedef struct Foo_u16: + uint16_t x; + + IF DEFINE_FEATURE_1: + ctypedef Foo_u16 FooConditional_u16; + + ctypedef struct Foo_i16: + int16_t x; + + ctypedef struct Foo_i8: + int8_t x; + + ctypedef struct NotReturnValue_i32: + int32_t x; + + ctypedef struct FooField: + Foo_i8 (*f)(); + void (*g)(NotReturnValue_i32); + + ctypedef struct Bar_i16__i16: + int16_t p; + int16_t q; + + ctypedef struct Bar_i8__i32: + int8_t p; + int32_t q; + + ctypedef Bar_i8__i32 IntBar_i32; + + ctypedef struct Bar_i8__bool: + int8_t p; + bool q; + + ctypedef Bar_i8__bool IntBar_bool; + + ctypedef IntBar_bool IntBoolBar; + + ctypedef struct Foo_i32: + int32_t x; + + ctypedef Foo_i32 WrapFoo_i32; + + ctypedef struct Bar_bool__bool: + bool p; + bool q; + + ctypedef Bar_bool__bool BoolBoolBar; + + ctypedef BoolBoolBar WrapBoolBoolBar; + + ctypedef struct Foo_bool: + bool x; + + ctypedef int8_t WrapNonZeroInt; + + ctypedef struct Foo_i64: + int64_t x; + + ctypedef Foo_i64 Transparent; + + ctypedef struct Foo_u8: + uint8_t x; + + IF DEFINE_FEATURE_2: + FooConditional_u16 double_feature(); + + int32_t fnA(); + + int16_t fnB(); + + Foo_i16 fnE(); + + void fnF(FooField f); + + Bar_i16__i16 fnG(); + + IntBar_i32 fnH(); + + IntBoolBar fnI(); + + WrapFoo_i32 fnJ(); + + WrapBoolBoolBar fnK(); + + Foo_bool fnL(); + + WrapNonZeroInt fnM(); + + Transparent fnN(); + + IF DEFINE_FEATURE_1: + Foo_u8 fnO(); + + Foo_u8 fnP(); diff --git a/tests/expectations/return_value_monomorphs_both.c b/tests/expectations/return_value_monomorphs_both.c new file mode 100644 index 000000000..629f71f2e --- /dev/null +++ b/tests/expectations/return_value_monomorphs_both.c @@ -0,0 +1,121 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +typedef struct Foo_u16 { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + +typedef struct Foo_i16 { + int16_t x; +} Foo_i16; + +typedef struct Foo_i8 { + int8_t x; +} Foo_i8; + +typedef struct NotReturnValue_i32 { + int32_t x; +} NotReturnValue_i32; + +typedef struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +} FooField; + +typedef struct Bar_i16__i16 { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct Bar_i8__i32 { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef struct Bar_i8__i32 IntBar_i32; + +typedef struct Bar_i8__bool { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct Foo_i32 { + int32_t x; +} Foo_i32; + +typedef struct Foo_i32 WrapFoo_i32; + +typedef struct Bar_bool__bool { + bool p; + bool q; +} Bar_bool__bool; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct Foo_bool { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct Foo_i64 { + int64_t x; +} Foo_i64; + +typedef struct Foo_i64 Transparent; + +typedef struct Foo_u8 { + uint8_t x; +} Foo_u8; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs_both.compat.c b/tests/expectations/return_value_monomorphs_both.compat.c new file mode 100644 index 000000000..8ef152d56 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_both.compat.c @@ -0,0 +1,129 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +typedef struct Foo_u16 { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + +typedef struct Foo_i16 { + int16_t x; +} Foo_i16; + +typedef struct Foo_i8 { + int8_t x; +} Foo_i8; + +typedef struct NotReturnValue_i32 { + int32_t x; +} NotReturnValue_i32; + +typedef struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +} FooField; + +typedef struct Bar_i16__i16 { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct Bar_i8__i32 { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef struct Bar_i8__i32 IntBar_i32; + +typedef struct Bar_i8__bool { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct Foo_i32 { + int32_t x; +} Foo_i32; + +typedef struct Foo_i32 WrapFoo_i32; + +typedef struct Bar_bool__bool { + bool p; + bool q; +} Bar_bool__bool; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct Foo_bool { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct Foo_i64 { + int64_t x; +} Foo_i64; + +typedef struct Foo_i64 Transparent; + +typedef struct Foo_u8 { + uint8_t x; +} Foo_u8; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.c b/tests/expectations/return_value_monomorphs_tag.c new file mode 100644 index 000000000..2bdaf00ae --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.c @@ -0,0 +1,121 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +struct Foo_u16 { + uint16_t x; +}; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + +struct Foo_i16 { + int16_t x; +}; + +struct Foo_i8 { + int8_t x; +}; + +struct NotReturnValue_i32 { + int32_t x; +}; + +struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +}; + +struct Bar_i16__i16 { + int16_t p; + int16_t q; +}; + +struct Bar_i8__i32 { + int8_t p; + int32_t q; +}; + +typedef struct Bar_i8__i32 IntBar_i32; + +struct Bar_i8__bool { + int8_t p; + bool q; +}; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +struct Foo_i32 { + int32_t x; +}; + +typedef struct Foo_i32 WrapFoo_i32; + +struct Bar_bool__bool { + bool p; + bool q; +}; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +struct Foo_bool { + bool x; +}; + +typedef int8_t WrapNonZeroInt; + +struct Foo_i64 { + int64_t x; +}; + +typedef struct Foo_i64 Transparent; + +struct Foo_u8 { + uint8_t x; +}; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs_tag.compat.c b/tests/expectations/return_value_monomorphs_tag.compat.c new file mode 100644 index 000000000..54ff29b22 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.compat.c @@ -0,0 +1,129 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +#include +#include +#include +#include + +struct Foo_u16 { + uint16_t x; +}; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + +struct Foo_i16 { + int16_t x; +}; + +struct Foo_i8 { + int8_t x; +}; + +struct NotReturnValue_i32 { + int32_t x; +}; + +struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +}; + +struct Bar_i16__i16 { + int16_t p; + int16_t q; +}; + +struct Bar_i8__i32 { + int8_t p; + int32_t q; +}; + +typedef struct Bar_i8__i32 IntBar_i32; + +struct Bar_i8__bool { + int8_t p; + bool q; +}; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +struct Foo_i32 { + int32_t x; +}; + +typedef struct Foo_i32 WrapFoo_i32; + +struct Bar_bool__bool { + bool p; + bool q; +}; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +struct Foo_bool { + bool x; +}; + +typedef int8_t WrapNonZeroInt; + +struct Foo_i64 { + int64_t x; +}; + +typedef struct Foo_i64 Transparent; + +struct Foo_u8 { + uint8_t x; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.pyx b/tests/expectations/return_value_monomorphs_tag.pyx new file mode 100644 index 000000000..66509a465 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.pyx @@ -0,0 +1,108 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + +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 *: + + cdef struct Foo_u16: + uint16_t x; + + IF DEFINE_FEATURE_1: + ctypedef Foo_u16 FooConditional_u16; + + cdef struct Foo_i16: + int16_t x; + + cdef struct Foo_i8: + int8_t x; + + cdef struct NotReturnValue_i32: + int32_t x; + + cdef struct FooField: + Foo_i8 (*f)(); + void (*g)(NotReturnValue_i32); + + cdef struct Bar_i16__i16: + int16_t p; + int16_t q; + + cdef struct Bar_i8__i32: + int8_t p; + int32_t q; + + ctypedef Bar_i8__i32 IntBar_i32; + + cdef struct Bar_i8__bool: + int8_t p; + bool q; + + ctypedef Bar_i8__bool IntBar_bool; + + ctypedef IntBar_bool IntBoolBar; + + cdef struct Foo_i32: + int32_t x; + + ctypedef Foo_i32 WrapFoo_i32; + + cdef struct Bar_bool__bool: + bool p; + bool q; + + ctypedef Bar_bool__bool BoolBoolBar; + + ctypedef BoolBoolBar WrapBoolBoolBar; + + cdef struct Foo_bool: + bool x; + + ctypedef int8_t WrapNonZeroInt; + + cdef struct Foo_i64: + int64_t x; + + ctypedef Foo_i64 Transparent; + + cdef struct Foo_u8: + uint8_t x; + + IF DEFINE_FEATURE_2: + FooConditional_u16 double_feature(); + + int32_t fnA(); + + int16_t fnB(); + + Foo_i16 fnE(); + + void fnF(FooField f); + + Bar_i16__i16 fnG(); + + IntBar_i32 fnH(); + + IntBoolBar fnI(); + + WrapFoo_i32 fnJ(); + + WrapBoolBoolBar fnK(); + + Foo_bool fnL(); + + WrapNonZeroInt fnM(); + + Transparent fnN(); + + IF DEFINE_FEATURE_1: + Foo_u8 fnO(); + + Foo_u8 fnP(); diff --git a/tests/expectations/swift_name.c b/tests/expectations/swift_name.c index 17ec2144f..1dbb279bf 100644 --- a/tests/expectations/swift_name.c +++ b/tests/expectations/swift_name.c @@ -11,6 +11,8 @@ typedef struct { uint8_t times; } SelfTypeTestStruct; +typedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct { Opaque *ptr; } PointerToOpaque; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.compat.c b/tests/expectations/swift_name.compat.c index d018ce833..354617857 100644 --- a/tests/expectations/swift_name.compat.c +++ b/tests/expectations/swift_name.compat.c @@ -11,6 +11,8 @@ typedef struct { uint8_t times; } SelfTypeTestStruct; +typedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct { Opaque *ptr; } PointerToOpaque; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.cpp b/tests/expectations/swift_name.cpp index 56d422c5a..2703c7feb 100644 --- a/tests/expectations/swift_name.cpp +++ b/tests/expectations/swift_name.cpp @@ -6,15 +6,15 @@ #include #include -template -struct Box; - struct Opaque; struct SelfTypeTestStruct { uint8_t times; }; +template +using Foo = const T*; + struct PointerToOpaque { Opaque *ptr; }; @@ -27,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(Box self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -Box SelfTypeTestStruct_should_not_exist_return_box() CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo SelfTypeTestStruct_should_not_exist_return_box() CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -49,7 +49,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(Box boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.pyx b/tests/expectations/swift_name.pyx index 3c2435a53..860a72301 100644 --- a/tests/expectations/swift_name.pyx +++ b/tests/expectations/swift_name.pyx @@ -14,6 +14,8 @@ cdef extern from *: ctypedef struct SelfTypeTestStruct: uint8_t times; + ctypedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + ctypedef struct PointerToOpaque: Opaque *ptr; @@ -23,9 +25,9 @@ cdef extern from *: void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self); - void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self); + void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self); - SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(); + Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self); @@ -45,7 +47,7 @@ cdef extern from *: void unnamed_argument(SelfTypeTestStruct*); - void free_function_should_not_exist_box(SelfTypeTestStruct *boxed); + void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct); diff --git a/tests/expectations/swift_name_both.c b/tests/expectations/swift_name_both.c index 4911679fa..ec9bc53a6 100644 --- a/tests/expectations/swift_name_both.c +++ b/tests/expectations/swift_name_both.c @@ -11,6 +11,8 @@ typedef struct SelfTypeTestStruct { uint8_t times; } SelfTypeTestStruct; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct PointerToOpaque { struct Opaque *ptr; } PointerToOpaque; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_both.compat.c b/tests/expectations/swift_name_both.compat.c index 592a8c7d5..99dfce345 100644 --- a/tests/expectations/swift_name_both.compat.c +++ b/tests/expectations/swift_name_both.compat.c @@ -11,6 +11,8 @@ typedef struct SelfTypeTestStruct { uint8_t times; } SelfTypeTestStruct; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct PointerToOpaque { struct Opaque *ptr; } PointerToOpaque; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.c b/tests/expectations/swift_name_tag.c index 370b88ae2..db534ce4f 100644 --- a/tests/expectations/swift_name_tag.c +++ b/tests/expectations/swift_name_tag.c @@ -11,6 +11,8 @@ struct SelfTypeTestStruct { uint8_t times; }; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + struct PointerToOpaque { struct Opaque *ptr; }; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.compat.c b/tests/expectations/swift_name_tag.compat.c index 89b1b2bd1..a27c95761 100644 --- a/tests/expectations/swift_name_tag.compat.c +++ b/tests/expectations/swift_name_tag.compat.c @@ -11,6 +11,8 @@ struct SelfTypeTestStruct { uint8_t times; }; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + struct PointerToOpaque { struct Opaque *ptr; }; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.pyx b/tests/expectations/swift_name_tag.pyx index 127fb3243..5a3443f65 100644 --- a/tests/expectations/swift_name_tag.pyx +++ b/tests/expectations/swift_name_tag.pyx @@ -14,6 +14,8 @@ cdef extern from *: cdef struct SelfTypeTestStruct: uint8_t times; + ctypedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + cdef struct PointerToOpaque: Opaque *ptr; @@ -23,9 +25,9 @@ cdef extern from *: void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self); - void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self); + void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self); - SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(); + Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self); @@ -45,7 +47,7 @@ cdef extern from *: void unnamed_argument(SelfTypeTestStruct*); - void free_function_should_not_exist_box(SelfTypeTestStruct *boxed); + void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct); diff --git a/tests/rust/const_generics_char.toml b/tests/rust/const_generics_char.toml new file mode 100644 index 000000000..135e56c35 --- /dev/null +++ b/tests/rust/const_generics_char.toml @@ -0,0 +1,2 @@ +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/const_generics_thru.toml b/tests/rust/const_generics_thru.toml new file mode 100644 index 000000000..135e56c35 --- /dev/null +++ b/tests/rust/const_generics_thru.toml @@ -0,0 +1,2 @@ +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/must_use.toml b/tests/rust/must_use.toml index 939df10c0..5342bf2d2 100644 --- a/tests/rust/must_use.toml +++ b/tests/rust/must_use.toml @@ -12,3 +12,6 @@ must_use = "MUST_USE_STRUCT" [enum] must_use = "MUST_USE_ENUM" + +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/return_value_monomorphs.rs b/tests/rust/return_value_monomorphs.rs new file mode 100644 index 000000000..1e800b63e --- /dev/null +++ b/tests/rust/return_value_monomorphs.rs @@ -0,0 +1,106 @@ +#[repr(C)] +pub struct Foo { + x: T, +} + +#[repr(C)] +pub struct NotReturnValue { + x: T, +} + +#[repr(C)] +pub struct FooField { + f: extern "C" fn() -> Foo, + g: extern "C" fn(NotReturnValue), +} + +#[repr(C)] +pub struct Bar { + p: P, + q: Q, +} + +#[repr(transparent)] +pub struct Transparent { + x: Foo, +} + +#[cfg(feature = "feature1")] +pub type FooConditional = Foo; + +pub struct Conditional; + +#[cfg(feature = "feature1")] +impl Conditional { + #[no_mangle] + #[cfg(feature = "feature2")] + pub extern "C" fn double_feature() -> FooConditional { todo!() } +} + +pub type IntBar = Bar; + +pub type IntBoolBar = IntBar; + +pub type WrapFoo = Foo; + +pub type BoolBoolBar = Bar; + +pub type WrapBoolBoolBar = BoolBoolBar; + +pub type WrapNonZeroInt = NonZero; + +// Negatie case: Not generic +#[no_mangle] +pub extern "C" fn fnA() -> i32 { todo!() } + +// Negative case: Transparent and underlying is not a monomorph +#[no_mangle] +pub extern "C" fn fnB() -> NonZero { todo!() } + +// Negative case: cbindgen does not support template functions in the first place +#[no_mangle] +pub extern "C" fn fnC() -> Foo { todo!() } + +// Negative case: Not emitted because opaque, but anyway would fail to compile because Option only has +// a forward declaration. +//#[no_mangle] +//pub extern "C" fn fnD() -> Option { todo!() } + +#[no_mangle] +pub extern "C" fn fnE() -> Foo { todo!() } + +#[no_mangle] +pub extern "C" fn fnF(f: FooField) {} + +#[no_mangle] +pub extern "C" fn fnG() -> Bar { todo!() } + +#[no_mangle] +pub extern "C" fn fnH() -> IntBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnI() -> IntBoolBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnJ() -> WrapFoo { todo!() } + +#[no_mangle] +pub extern "C" fn fnK() -> WrapBoolBoolBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnL() -> Foo { todo!() } + +// Negative case: transparent and underlying is not a template type +#[no_mangle] +pub extern "C" fn fnM() -> WrapNonZeroInt { todo!() } + +#[no_mangle] +pub extern "C" fn fnN() -> Transparent { todo!() } + +#[no_mangle] +#[cfg(feature = "feature1")] +pub extern "C" fn fnO() -> Foo { todo!() } + +// This one should cause Foo to appear a second time, because the cfg differs +#[no_mangle] +pub extern "C" fn fnP() -> Foo { todo!() } diff --git a/tests/rust/return_value_monomorphs.toml b/tests/rust/return_value_monomorphs.toml new file mode 100644 index 000000000..282d4cfee --- /dev/null +++ b/tests/rust/return_value_monomorphs.toml @@ -0,0 +1,13 @@ +header = """ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif +""" + +[export] +instantiate_return_value_monomorphs = true + +[defines] +"feature = feature1" = "DEFINE_FEATURE_1" +"feature = feature2" = "DEFINE_FEATURE_2" diff --git a/tests/rust/swift_name.rs b/tests/rust/swift_name.rs index 01cfdbe6b..808935262 100644 --- a/tests/rust/swift_name.rs +++ b/tests/rust/swift_name.rs @@ -1,3 +1,9 @@ +// A stand-in for Box, since Box is undefined behavior in C++ +#[repr(transparent)] +pub struct Foo { + data: *const T, +} + #[export_name="rust_print_hello_world"] pub extern fn say_hello() { println!("Hello, World!"); @@ -23,13 +29,13 @@ impl SelfTypeTestStruct { #[export_name="SelfTypeTestStruct_should_not_exist_box"] #[no_mangle] - pub extern fn should_not_exist_box(self: Box) { + pub extern fn should_not_exist_box(self: Foo) { println!("should_not_exist_box"); } #[export_name="SelfTypeTestStruct_should_not_exist_return_box"] #[no_mangle] - pub extern fn should_not_exist_box() -> Box { + pub extern fn should_not_exist_box() -> Foo { println!("should_not_exist_box"); } @@ -92,7 +98,7 @@ pub extern fn unnamed_argument(_: &mut SelfTypeTestStruct) { #[no_mangle] #[allow(unused_variables)] -pub extern fn free_function_should_not_exist_box(boxed: Box) { +pub extern fn free_function_should_not_exist_box(boxed: Foo) { println!("free_function_should_not_exist_box"); } diff --git a/tests/tests.rs b/tests/tests.rs index eebabefbe..97bdf21f5 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -144,9 +144,6 @@ fn compile( command.arg("-Wno-attributes"); // clang warns about unused const variables. command.arg("-Wno-unused-const-variable"); - // clang also warns about returning non-instantiated templates (they could - // be specialized, but they're not so it's fine). - command.arg("-Wno-return-type-c-linkage"); // deprecated warnings should not be errors as it's intended command.arg("-Wno-deprecated-declarations"); @@ -189,7 +186,21 @@ fn compile( println!("Running: {:?}", command); let out = command.output().expect("failed to compile"); - assert!(out.status.success(), "Output failed to compile: {:?}", out); + if !out.status.success() { + let stdout = match str::from_utf8(&out.stdout) { + Ok(s) => s.to_string(), + Err(_) => format!("{:?}", out.stdout), + }; + let stderr = match str::from_utf8(&out.stderr) { + Ok(s) => s.to_string(), + Err(_) => format!("{:?}", out.stderr), + }; + println!("Output failed to compile: {:?}", out.status); + println!("=== STDOUT ===\n{}", stdout); + println!("=== STDERR ===\n{}", stderr); + println!("=============="); + assert!(out.status.success()); + } if object.exists() { fs::remove_file(object).unwrap();