diff --git a/docs.md b/docs.md index c8ce9f4f..ad5dcc18 100644 --- a/docs.md +++ b/docs.md @@ -299,7 +299,76 @@ fn bar() -> Foo { .. } // Will be emitted as `struct foo bar();` ### Struct Annotations -* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming. +* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output + struct. These names will be output verbatim, and are not eligible for renaming. + +* transparent-typedef -- when emitting the typedef for a transparent struct, mark it as + transparent. All references to the struct will be replaced with the type of its underlying NZST + field, effectively making the struct invisible on the FFI side. For example, consider the + following Rust code: + + ```rust + #[repr(transparent)] + pub struct Handle { + ptr: NonNull, + } + + pub struct Foo { } + + #[no_mangle] + pub extern "C" fn foo_operation(foo: Option>) { } + ``` + + By default, the exported C++ code would fail to compile, because the function takes `Option<...>` + (which is an opaque type) by value: + + ```cpp + template + struct Option; + + template + using Handle = T; + + struct Foo; + + void foo_operation(Option> foo); + ``` + + If we annotate `Handle` with `transparent-typedef` (leaving the rest of the code unchanged): + ```rust + /// cbindgen:transparent-typedef + #[repr(transparent)] + pub struct Handle { + ptr: NonNull, + } + ``` + + Then cbindgen is able to simplify the exported C++ code to just: + ```cpp + struct Foo; + + void foo_operation(Foo* foo); + ``` + + NOTE: This annotation does _NOT_ affect user-defined type aliases for transparent structs. If we + we adjust the previous example to use a type alias: + + ```rust + type NullableFooHandle = Option>; + + #[no_mangle] + pub extern "C" fn foo_operation(foo: NullableFooHandle) { } + ``` + + Then the exported code will use it as expected: + + ```cpp + struct Foo; + + using NullableFooHandle = Foo*; + + void foo_operation(NullableFooHandle foo); + ``` The rest are just local overrides for the same options found in the cbindgen.toml: @@ -316,27 +385,25 @@ The rest are just local overrides for the same options found in the cbindgen.tom / etc(if any). The idea is for this to be used to annotate the operator with attributes, for example: -```rust -/// cbindgen:eq-attributes=MY_ATTRIBUTES -#[repr(C)] -pub struct Foo { .. } -``` - -Will generate something like: + ```rust + /// cbindgen:eq-attributes=MY_ATTRIBUTES + #[repr(C)] + pub struct Foo { .. } + ``` -``` - MY_ATTRIBUTES bool operator==(const Foo& other) const { - ... - } -``` + Will generate something like: -Combined with something like: + ``` + MY_ATTRIBUTES bool operator==(const Foo& other) const { + ... + } + ``` -``` -#define MY_ATTRIBUTES [[nodiscard]] -``` + Combined with something like: -for example. + ``` + #define MY_ATTRIBUTES [[nodiscard]] + ``` ### Enum Annotations diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index d47919b9..a649a0fc 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -368,7 +368,7 @@ impl Builder { let mut result = Parse::new(); if self.std_types { - result.add_std_types(); + result.add_std_types(self.config.language); } for x in &self.srcs { diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index ca6499d8..d75b0068 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -18,6 +18,7 @@ use crate::bindgen::ir::{ }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::writer::SourceWriter; use crate::bindgen::Bindings; @@ -605,6 +606,18 @@ impl Item for Constant { } } +impl ResolveTransparentTypes for Constant { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // NOTE: We also need to simplify the literal initializer value to match the underlying + // type, but that is true for all transparent structs (not just transparent-typedef + // structs), and is handled by the `write` method below. + Some(Constant { + ty: self.ty.transparent_alias(library, GenericParams::empty())?, + ..self.clone() + }) + } +} + impl Constant { pub fn write_declaration( &self, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 8927b8be..80a29b8c 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -2,6 +2,7 @@ * 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::borrow::Cow; use std::io::Write; use syn::ext::IdentExt; @@ -20,6 +21,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::{CowIsOwned, IterCow, ResolveTransparentTypes}; use crate::bindgen::writer::{ListType, SourceWriter}; #[allow(clippy::large_enum_variant)] @@ -248,12 +250,6 @@ impl EnumVariant { } } - fn simplify_standard_types(&mut self, config: &Config) { - if let VariantBody::Body { ref mut body, .. } = self.body { - body.simplify_standard_types(config); - } - } - fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { if let VariantBody::Body { ref body, .. } = self.body { body.add_dependencies(library, out); @@ -641,6 +637,51 @@ impl Item for Enum { } } +impl ResolveTransparentTypes for Enum { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // If the enum uses inline tag fields, every variant struct has one. Skip resolving them. + let params = Self::resolve_generic_params(library, &self.generic_params); + let skip_inline_tag_field = Self::inline_tag_field(&self.repr); + let variants: Vec<_> = self + .variants + .iter() + .cow_map(|v| match v.body { + VariantBody::Body { + ref name, + ref body, + inline, + inline_casts, + } => { + let fields = + Self::resolve_fields(library, &body.fields, ¶ms, skip_inline_tag_field); + let Cow::Owned(fields) = fields else { + return None; + }; + Some(EnumVariant { + body: VariantBody::Body { + name: name.clone(), + body: Struct { + fields, + ..body.clone() + }, + inline, + inline_casts, + }, + ..v.clone() + }) + } + VariantBody::Empty(..) => None, + }) + .collect(); + + (params.cow_is_owned() || variants.iter().any_owned()).then(|| Enum { + generic_params: params.into_owned(), + variants: variants.into_iter().map(Cow::into_owned).collect(), + ..self.clone() + }) + } +} + impl Enum { /// Emit the tag enum and convenience methods for it. /// For enums with data this is only a part of the output, @@ -1496,10 +1537,4 @@ impl Enum { } } } - - pub fn simplify_standard_types(&mut self, config: &Config) { - for variant in &mut self.variants { - variant.simplify_standard_types(config); - } - } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index f25d2f88..327258e3 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -2,6 +2,7 @@ * 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::borrow::Cow; use std::collections::HashMap; use syn::ext::IdentExt; @@ -9,11 +10,14 @@ 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::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::{CowIsOwned, IterCow, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -115,13 +119,6 @@ impl Function { &self.path } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.ret.simplify_standard_types(config); - for arg in &mut self.args { - arg.ty.simplify_standard_types(config); - } - } - pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { self.ret.add_dependencies(library, out); for arg in &self.args { @@ -219,6 +216,29 @@ impl Function { } } +impl ResolveTransparentTypes for Function { + fn resolve_transparent_types(&self, library: &Library) -> Option { + let empty = GenericParams::empty(); + let ret = self.ret.transparent_alias_cow(library, empty); + let args: Vec<_> = self + .args + .iter() + .cow_map(|arg| { + Some(FunctionArgument { + ty: arg.ty.transparent_alias(library, empty)?, + ..arg.clone() + }) + }) + .collect(); + + (ret.cow_is_owned() || args.iter().any_owned()).then(|| Function { + ret: ret.into_owned(), + args: args.into_iter().map(Cow::into_owned).collect(), + ..self.clone() + }) + } +} + trait SynFnArgHelpers { fn as_argument(&self) -> Result, String>; } diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 4610641c..bd938e2a 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -25,11 +25,11 @@ pub struct GenericParam { } impl GenericParam { - pub fn new_type_param(name: &str) -> Self { + pub fn new_type_param(name: &str, default: Option) -> Self { GenericParam { name: Path::new(name), ty: GenericParamType::Type, - default: None, + default, } } @@ -80,6 +80,9 @@ impl GenericParam { pub fn name(&self) -> &Path { &self.name } + pub fn default(&self) -> Option<&GenericArgument> { + self.default.as_ref() + } } #[derive(Default, Debug, Clone)] diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 7816a294..75dd35bf 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -9,6 +9,7 @@ use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, GenericParams, Item, ItemContainer, Path, Type, }; use crate::bindgen::library::Library; +use crate::bindgen::transparent::ResolveTransparentTypes; #[derive(Debug, Clone)] pub struct Static { @@ -62,10 +63,6 @@ impl Static { documentation, } } - - pub fn simplify_standard_types(&mut self, config: &Config) { - self.ty.simplify_standard_types(config); - } } impl Item for Static { @@ -113,3 +110,12 @@ impl Item for Static { self.ty.add_dependencies(library, out); } } + +impl ResolveTransparentTypes for Static { + fn resolve_transparent_types(&self, library: &Library) -> Option { + Some(Static { + ty: self.ty.transparent_alias(library, GenericParams::empty())?, + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 03e1c153..6040c01a 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -66,8 +66,10 @@ pub enum ItemContainer { Typedef(Typedef), } -impl ItemContainer { - pub fn deref(&self) -> &dyn Item { +impl std::ops::Deref for ItemContainer { + type Target = dyn Item + 'static; + + fn deref(&self) -> &Self::Target { match *self { ItemContainer::Constant(ref x) => x, ItemContainer::Static(ref x) => x, diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4527e3ca..5356939c 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -2,15 +2,19 @@ * 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::borrow::Cow; + use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::ResolveTransparentTypes; #[derive(Debug, Clone)] pub struct OpaqueItem { @@ -55,6 +59,30 @@ impl OpaqueItem { documentation, } } + + pub fn transparent_alias(&self, args: &[GenericArgument]) -> Option { + if !self.is_generic() { + return None; + } + let Some(GenericArgument::Type(ty)) = args.first() else { + return None; + }; + let ty = match self.name() { + // NonNull is always transparent, but needs to transform `T` + "NonNull" => Type::Ptr { + ty: Box::new(ty.clone()), + is_const: false, + is_nullable: false, + is_ref: false, + }, + // NonZero is only transparent if T is zeroable + "NonZero" => ty.make_zeroable(false)?, + // Option is only transparent if T is non-zeroable or non-nullable + "Option" => ty.make_zeroable(true).or_else(|| ty.make_nullable())?, + _ => return None, + }; + Some(ty) + } } impl Item for OpaqueItem { @@ -136,3 +164,15 @@ impl Item for OpaqueItem { out.insert_opaque(self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for OpaqueItem { + fn resolve_transparent_types(&self, library: &Library) -> Option { + match Self::resolve_generic_params(library, &self.generic_params) { + Cow::Owned(generic_params) => Some(OpaqueItem { + generic_params, + ..self.clone() + }), + _ => None, + } + } +} diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index d805d69c..ba193faa 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -18,6 +18,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::SourceWriter; @@ -160,18 +161,16 @@ impl Struct { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - for field in &mut self.fields { - field.ty.simplify_standard_types(config); - } - } - /// 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 transparent_alias(&self, args: &[GenericArgument]) -> Option { + self.as_typedef() + .and_then(|typedef| typedef.transparent_alias(args)) } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { @@ -402,3 +401,16 @@ impl Item for Struct { out.insert_struct(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Struct { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = Self::resolve_generic_params(library, &self.generic_params); + let fields = Self::resolve_fields(library, &self.fields, ¶ms, false); + (params.cow_is_owned() || fields.cow_is_owned()).then(|| Struct { + generic_params: params.into_owned(), + fields: fields.into_owned(), + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 2d0d692a..231fc377 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -3,15 +3,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; - use syn::ext::IdentExt; -use crate::bindgen::config::{Config, Language}; +use crate::bindgen::config::Config; 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::transparent::{CowIsOwned, IterCow, TransparentTypeResolver}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -519,61 +519,6 @@ impl Type { } } - fn simplified_type(&self, config: &Config) -> Option { - let path = match *self { - Type::Path(ref p) => p, - _ => return None, - }; - - if path.generics().is_empty() { - return None; - } - - if path.generics().len() != 1 { - return None; - } - - let unsimplified_generic = match path.generics()[0] { - GenericArgument::Type(ref ty) => ty, - GenericArgument::Const(_) => return None, - }; - - let generic = match unsimplified_generic.simplified_type(config) { - Some(generic) => Cow::Owned(generic), - None => Cow::Borrowed(unsimplified_generic), - }; - match path.name() { - "Option" => generic - .make_nullable() - .or_else(|| generic.make_zeroable(true)), - "NonNull" => Some(Type::Ptr { - ty: Box::new(generic.into_owned()), - is_const: false, - is_nullable: false, - is_ref: false, - }), - "NonZero" => generic.make_zeroable(false), - "Box" if config.language != Language::Cxx => Some(Type::Ptr { - ty: Box::new(generic.into_owned()), - is_const: false, - is_nullable: false, - is_ref: false, - }), - "SyncUnsafeCell" | "UnsafeCell" | "Cell" => Some(generic.into_owned()), - "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => { - Some(generic.into_owned()) - } - _ => None, - } - } - - pub fn simplify_standard_types(&mut self, config: &Config) { - self.visit_types(|ty| ty.simplify_standard_types(config)); - if let Some(ty) = self.simplified_type(config) { - *self = ty; - } - } - pub fn replace_self_with(&mut self, self_ty: &Path) { if let Type::Path(ref mut generic_path) = *self { generic_path.replace_self_with(self_ty); @@ -627,6 +572,85 @@ impl Type { } } + /// Convenience wrapper for callers who prefer `Cow` result over `Option`. + pub fn transparent_alias_cow<'a>( + &'a self, + library: &Library, + params: &GenericParams, + ) -> Cow<'a, Type> { + self.transparent_alias(library, params) + .map_or_else(|| Cow::Borrowed(self), Cow::Owned) + } + + /// If this type is transparent, recursively replace it with whatever type it aliases. + pub fn transparent_alias(&self, library: &Library, params: &GenericParams) -> Option { + match *self { + Type::Ptr { + ref ty, + is_const, + is_nullable, + is_ref, + } => Some(Type::Ptr { + ty: Box::new(ty.transparent_alias(library, params)?), + is_const, + is_nullable, + is_ref, + }), + Type::Path(ref generic_path) => { + let path = generic_path.path(); + if params.0.iter().any(|p| p.name() == path) { + return None; // Don't try to resolve template parameters! + } + // Resolve the generics first -- they may change even if this type isn't transparent + let generics = generic_path.generics(); + let new_generics: Vec<_> = generics + .iter() + .cow_map(|arg| match arg { + GenericArgument::Type(ty) => Some(GenericArgument::Type( + ty.transparent_alias(library, params)?, + )), + _ => None, + }) + .collect(); + let new_generics = new_generics + .iter() + .any_owned() + .then(|| new_generics.into_iter().map(Cow::into_owned).collect()); + let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); + let ty = TransparentTypeResolver::transparent_alias_for_path( + path, generics, library, params, + ); + ty.or_else(|| Some(Type::Path(GenericPath::new(path.clone(), new_generics?)))) + } + Type::Primitive(_) => None, + Type::Array(ref ty, ref expr) => Some(Type::Array( + Box::new(ty.transparent_alias(library, params)?), + expr.clone(), + )), + Type::FuncPtr { + ref ret, + ref args, + is_nullable, + never_return, + } => { + let ret = ret.transparent_alias_cow(library, params); + let args: Vec<_> = args + .iter() + .cow_map(|(name, ty)| { + Some((name.clone(), ty.transparent_alias(library, params)?)) + }) + .collect(); + + (ret.cow_is_owned() || args.iter().any_owned()).then(|| Type::FuncPtr { + ret: Box::new(ret.into_owned()), + args: args.into_iter().map(Cow::into_owned).collect(), + is_nullable, + never_return, + }) + } + } + } + pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type { match *self { Type::Ptr { @@ -705,7 +729,7 @@ impl Type { out.items.insert(path.clone()); for item in &items { - item.deref().add_dependencies(library, out); + item.add_dependencies(library, out); } for item in items { out.order.push(item); @@ -751,8 +775,7 @@ impl Type { let path = generic.path(); if let Some(items) = library.get_items(path) { for item in items { - item.deref() - .instantiate_monomorph(generic.generics(), library, out); + item.instantiate_monomorph(generic.generics(), library, out); } } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e775a4e8..42cc1d38 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -16,6 +16,7 @@ use crate::bindgen::ir::{ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; /// A type alias that is represented as a C typedef #[derive(Debug, Clone)] @@ -30,6 +31,9 @@ pub struct Typedef { } impl Typedef { + // Name of the annotation that identifies a transparent typedef. + pub const TRANSPARENT_TYPEDEF: &'static str = "transparent-typedef"; + pub fn load(item: &syn::ItemType, mod_cfg: Option<&Cfg>) -> Result { if let Some(x) = Type::load(&item.ty)? { let path = Path::new(item.ident.unraw().to_string()); @@ -66,10 +70,6 @@ impl Typedef { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.aliased.simplify_standard_types(config); - } - // Used to convert a transparent Struct to a Typedef. pub fn new_from_struct_field(item: &Struct, field: &Field) -> Self { Self { @@ -102,6 +102,19 @@ impl Typedef { } } + pub fn transparent_alias(&self, args: &[GenericArgument]) -> Option { + matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { + // Specialize the aliased type (if needed) and return it. We don't need to resolve + // params, because our caller processes transparent aliases iteratively to fixpoint. + if self.is_generic() { + let mappings = self.generic_params.call(self.path.name(), args); + self.aliased.specialize(&mappings) + } else { + self.aliased.clone() + } + }) + } + 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. @@ -192,3 +205,16 @@ impl Item for Typedef { out.insert_typedef(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Typedef { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = Self::resolve_generic_params(library, &self.generic_params); + let aliased = self.aliased.transparent_alias_cow(library, ¶ms); + (params.cow_is_owned() || aliased.cow_is_owned()).then(|| Typedef { + aliased: aliased.into_owned(), + generic_params: params.into_owned(), + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 9c425837..e60c3de5 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -15,6 +15,7 @@ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -94,12 +95,6 @@ impl Union { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - for field in &mut self.fields { - field.ty.simplify_standard_types(config); - } - } - 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. @@ -257,3 +252,15 @@ impl Item for Union { out.insert_union(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Union { + fn resolve_transparent_types(&self, library: &Library) -> Option { + let params = Self::resolve_generic_params(library, &self.generic_params); + let fields = Self::resolve_fields(library, &self.fields, ¶ms, false); + (params.cow_is_owned() || fields.cow_is_owned()).then(|| Union { + generic_params: params.into_owned(), + fields: fields.into_owned(), + ..self.clone() + }) + } +} diff --git a/src/bindgen/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index 065bade2..6b693ee3 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -159,12 +159,7 @@ pub trait LanguageBackend: Sized { fn write_items(&mut self, out: &mut SourceWriter, b: &Bindings) { for item in &b.items { - if item - .deref() - .annotations() - .bool("no-export") - .unwrap_or(false) - { + if item.annotations().bool("no-export").unwrap_or(false) { continue; } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f..0346dee3 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::transparent::TransparentTypeResolver; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -61,8 +62,8 @@ impl Library { } pub fn generate(mut self) -> Result { + self.resolve_transparent_types(); self.transfer_annotations(); - self.simplify_standard_types(); match self.config.function.sort_by.unwrap_or(self.config.sort_by) { SortKey::Name => self.functions.sort_by(|x, y| x.path.cmp(&y.path)), @@ -95,7 +96,7 @@ impl Library { if let Some(items) = self.get_items(&path) { if dependencies.items.insert(path) { for item in &items { - item.deref().add_dependencies(&self, &mut dependencies); + item.add_dependencies(&self, &mut dependencies); } for item in items { dependencies.order.push(item); @@ -318,6 +319,34 @@ impl Library { } } + fn resolve_transparent_types(&mut self) { + let resolver = TransparentTypeResolver; + + let constants = resolver.resolve_items(self, &self.constants); + resolver.install_items(constants, &mut self.constants); + + let globals = resolver.resolve_items(self, &self.globals); + resolver.install_items(globals, &mut self.globals); + + let enums = resolver.resolve_items(self, &self.enums); + resolver.install_items(enums, &mut self.enums); + + let structs = resolver.resolve_items(self, &self.structs); + resolver.install_items(structs, &mut self.structs); + + let unions = resolver.resolve_items(self, &self.unions); + resolver.install_items(unions, &mut self.unions); + + let opaque_items = resolver.resolve_items(self, &self.opaque_items); + resolver.install_items(opaque_items, &mut self.opaque_items); + + let typedefs = resolver.resolve_items(self, &self.typedefs); + resolver.install_items(typedefs, &mut self.typedefs); + + let functions = resolver.resolve_functions(self, &self.functions); + resolver.install_functions(functions, &mut self.functions); + } + fn resolve_declaration_types(&mut self) { if !self.config.style.generate_tag() { return; @@ -367,29 +396,6 @@ impl Library { } } - fn simplify_standard_types(&mut self) { - let config = &self.config; - - self.structs.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.enums.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.unions.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.globals.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.typedefs.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - for x in &mut self.functions { - x.simplify_standard_types(config); - } - } - fn instantiate_monomorphs(&mut self) { // Collect a list of monomorphs let mut monomorphs = Monomorphs::default(); diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 5d788211..53953072 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -53,6 +53,7 @@ mod monomorph; mod parser; mod rename; mod reserved; +mod transparent; mod utilities; mod writer; diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 13fa3f7e..8f019d51 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -12,11 +12,12 @@ use syn::ext::IdentExt; use crate::bindgen::bitflags; use crate::bindgen::cargo::{Cargo, PackageRef}; -use crate::bindgen::config::{Config, ParseConfig}; +use crate::bindgen::config::{Config, Language, 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, GenericArgument, + GenericParam, GenericParams, GenericPath, ItemMap, OpaqueItem, Path, Static, Struct, Type, + Typedef, Union, }; use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemHelpers}; @@ -438,39 +439,77 @@ impl Parse { } } - pub fn add_std_types(&mut self) { - let mut add_opaque = |path: &str, generic_params: Vec<&str>| { - let path = Path::new(path); - let generic_params: Vec<_> = generic_params - .into_iter() - .map(GenericParam::new_type_param) - .collect(); - self.opaque_items.try_insert(OpaqueItem::new( - path, - GenericParams(generic_params), - None, - AnnotationSet::new(), - Documentation::none(), - )) - }; + fn create_generic_params(param_names: Vec<&str>) -> Vec { + param_names + .iter() + .map(|name| GenericParam::new_type_param(name, None)) + .collect() + } + + fn add_opaque(&mut self, path: &str, generic_params: Vec<&str>) { + self.opaque_items.try_insert(OpaqueItem::new( + Path::new(path), + GenericParams(Self::create_generic_params(generic_params)), + None, + AnnotationSet::new(), + Documentation::none(), + )); + } + + fn add_transparent_typedef(&mut self, path: &str, aliased: Type, generic_params: Vec<&str>) { + let mut annotations = AnnotationSet::new(); + annotations.add_default(Typedef::TRANSPARENT_TYPEDEF, AnnotationValue::Bool(true)); + self.typedefs.try_insert(Typedef::new( + Path::new(path), + GenericParams(Self::create_generic_params(generic_params)), + aliased, + None, + annotations, + Documentation::none(), + )); + } + + pub fn add_std_types(&mut self, language: Language) { + // Always opaque + self.add_opaque("String", vec![]); + self.add_opaque("RefCell", vec!["T"]); + self.add_opaque("Rc", vec!["T"]); + self.add_opaque("Arc", vec!["T"]); + self.add_opaque("Result", vec!["T", "E"]); + self.add_opaque("Vec", vec!["T"]); + self.add_opaque("HashMap", vec!["K", "V", "Hasher"]); + self.add_opaque("BTreeMap", vec!["K", "V"]); + self.add_opaque("HashSet", vec!["T"]); + self.add_opaque("BTreeSet", vec!["T"]); + self.add_opaque("LinkedList", vec!["T"]); + self.add_opaque("VecDeque", vec!["T"]); + + // Registered as opaque, but potentially transparent (see OpaqueItem::transparent_alias). + self.add_opaque("Option", vec!["T"]); + self.add_opaque("NonNull", vec!["T"]); + self.add_opaque("NonZero", vec!["T"]); + + // Opaque in C++ but transparent in C + let tpath = Type::Path(GenericPath::new(Path::new("T"), vec![])); + if language == Language::Cxx { + self.add_opaque("Box", vec!["T"]); + self.add_opaque("ManuallyDrop", vec!["T"]); + self.add_opaque("MaybeUninit", vec!["T"]); + self.add_opaque("Pin", vec!["T"]); + } else { + // NOTE: Box acts like NonNull in C, so emit it as a transparent typedef + let generics = vec![GenericArgument::Type(tpath.clone())]; + let alias = Type::Path(GenericPath::new(Path::new("NonNull"), generics)); + self.add_transparent_typedef("Box", alias, vec!["T"]); + self.add_transparent_typedef("ManuallyDrop", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("MaybeUninit", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("Pin", tpath.clone(), vec!["T"]); + } - add_opaque("String", vec![]); - add_opaque("Box", vec!["T"]); - add_opaque("RefCell", vec!["T"]); - add_opaque("Rc", vec!["T"]); - add_opaque("Arc", vec!["T"]); - add_opaque("Result", vec!["T", "E"]); - add_opaque("Option", vec!["T"]); - add_opaque("NonNull", vec!["T"]); - add_opaque("Vec", vec!["T"]); - add_opaque("HashMap", vec!["K", "V", "Hasher"]); - add_opaque("BTreeMap", vec!["K", "V"]); - add_opaque("HashSet", vec!["T"]); - add_opaque("BTreeSet", vec!["T"]); - add_opaque("LinkedList", vec!["T"]); - add_opaque("VecDeque", vec!["T"]); - add_opaque("ManuallyDrop", vec!["T"]); - add_opaque("MaybeUninit", vec!["T"]); + // Always transparent + self.add_transparent_typedef("Cell", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("SyncUnsafeCell", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("UnsafeCell", tpath.clone(), vec!["T"]); } pub fn extend_with(&mut self, other: &Parse) { diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs new file mode 100644 index 00000000..c948ecd8 --- /dev/null +++ b/src/bindgen/transparent.rs @@ -0,0 +1,227 @@ +use std::borrow::Cow; +use std::collections::HashMap; + +use crate::bindgen::ir::{ + Field, Function, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, ItemMap, + Path, Type, +}; +use crate::bindgen::library::Library; + +/// Helper trait that makes it easier to work with `Cow` in iterators +// NOTE: 'i is the lifetime of the iterator itself, and 't is the lifetime of references it returns +pub trait IterCow<'i, 't: 'i, T: Clone + 't>: Iterator + 'i { + /// Maps from `&T` to `Cow<'t, T>` using the provided function. If the function returns `Some` + /// result, it is returned as `Cow::Owned`; otherwise, return the item as `Cow::Borrowed`. + // NOTE: MSRV 1.70 requires us to return `Box` because support for returning `impl + // Iterator` from trait methods didn't land until 1.75. Which in turn requires the lifetime 'i. + fn cow_map(self, f: F) -> Box> + 'i> + where + F: FnMut(&T) -> Option + 'i, + Self: Iterator; + + /// True if any item is `Cow::Owned` + fn any_owned(self) -> bool + where + Self: Iterator>; +} + +// Blanket implementation for all iterators +impl<'i, 't: 'i, T: Clone + 't, I: Iterator + 'i> IterCow<'i, 't, T> for I { + fn cow_map(self, mut f: F) -> Box> + 'i> + where + F: FnMut(&T) -> Option + 'i, + Self: Iterator, + { + Box::new(self.map(move |item| f(item).map_or_else(|| Cow::Borrowed(item), Cow::Owned))) + } + + fn any_owned(mut self) -> bool + where + Self: Iterator>, + { + self.any(|item| matches!(item, Cow::Owned(_))) + } +} + +/// Extension trait that compenates for `Cow::is_owned` being unstable +pub trait CowIsOwned { + fn cow_is_owned(&self) -> bool; +} +impl CowIsOwned for Cow<'_, T> { + fn cow_is_owned(&self) -> bool { + matches!(self, Cow::Owned(_)) + } +} + +pub trait ResolveTransparentTypes: Sized { + /// Attempts to resolve transparent aliases for all `Type` instances in this item. This includes + /// directly embedded types as well as generic parameter defaults, if any. + fn resolve_transparent_types(&self, library: &Library) -> Option; + + /// Attempts to resolve transparent aliases for the types of a slice of fields. A `Cow::Owned` + /// result means at least one field was modified as a result; otherwise, the original fields are + /// returned as a `Cow::Borrowed` result. + fn resolve_fields<'a>( + library: &Library, + fields: &'a Vec, + params: &GenericParams, + mut skip_first: bool, + ) -> Cow<'a, Vec> { + let new_fields: Vec<_> = fields + .iter() + .cow_map(|f| { + // Ignore the inline Tag field, if any (it's always first, when present at all) + if skip_first { + skip_first = false; + None + } else { + Some(Field { + ty: f.ty.transparent_alias(library, params)?, + ..f.clone() + }) + } + }) + .collect(); + + if new_fields.iter().any_owned() { + Cow::Owned(new_fields.into_iter().map(Cow::into_owned).collect()) + } else { + Cow::Borrowed(fields) + } + } + + /// Attempts to resolve transparent aliases for the types of default values in a generic + /// parameter list. A `Cow::Owned` return value means at least one field was modified as a + /// result; otherwise, the original params are returned as a `Cow::Borrowed` value. + fn resolve_generic_params<'a>( + library: &Library, + params: &'a GenericParams, + ) -> Cow<'a, GenericParams> { + let new_params: Vec<_> = params + .iter() + .cow_map(|param| match param.default() { + Some(GenericArgument::Type(ty)) => { + // NOTE: Param defaults can reference other params, so forward the param list to + // the type resolution to allow for proper substitutions to be made. + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + }) + .collect(); + + if new_params.iter().any_owned() { + Cow::Owned(GenericParams( + new_params.into_iter().map(Cow::into_owned).collect(), + )) + } else { + Cow::Borrowed(params) + } + } +} + +pub type ResolvedItems = HashMap; + +/// An indirection that allows to generalize the two-stage process of resolving transparent +/// types. We first call a `resolve_XXX` function to resolve transparent aliases and store the +/// results in a hashmap, using a borrowed reference to the `Library` to resolve the types. In the +/// second step, we call an `install_XXX` function to update a mutable reference to the `Library`. +pub struct TransparentTypeResolver; + +impl TransparentTypeResolver { + /// Attempts to resolve a path as a transparent alias. Even if this function returns None, the + /// caller has also resolved the generics and may need to return them. + pub fn transparent_alias_for_path( + path: &Path, + generics: &[GenericArgument], + library: &Library, + params: &GenericParams, + ) -> Option { + let Some(items) = library.get_items(path) else { + warn!("Unknown type {path:?}"); + return None; + }; + let mut items = items.into_iter(); + let item = items.next()?; + if let Some(other_item) = items.next() { + warn!("Found multiple resolved types for {path:?}: {item:?} and. {other_item:?}"); + return None; + } + + // Only some item types can ever be transparent -- handle them directly (not via `Item`) + let resolved_type = match item { + ItemContainer::Typedef(t) => t.transparent_alias(generics)?, + ItemContainer::Struct(s) => s.transparent_alias(generics)?, + ItemContainer::OpaqueItem(o) => o.transparent_alias(generics)?, + _ => return None, + }; + + // The resolved type may itself be transparent, so recurse on it + resolved_type + .transparent_alias(library, params) + .or(Some(resolved_type)) + } + + pub fn resolve_items(&self, library: &Library, items: &ItemMap) -> ResolvedItems + where + T: ResolveTransparentTypes + Item + Clone, + { + let mut resolved = Default::default(); + let mut i = 0; + items.for_all_items(|item| { + Self::resolve_item(item, i, &mut resolved, library); + i += 1; + }); + resolved + } + pub fn install_items(&self, mut resolved: ResolvedItems, items: &mut ItemMap) + where + T: ResolveTransparentTypes + Item + Clone, + { + let mut i = 0; + items.for_all_items_mut(|item| { + Self::install_item(item, i, &mut resolved); + i += 1; + }); + } + + // Functions do not impl Item + pub fn resolve_functions( + &self, + library: &Library, + items: &[Function], + ) -> ResolvedItems { + let mut functions = Default::default(); + for (i, item) in items.iter().enumerate() { + Self::resolve_item(item, i, &mut functions, library); + } + functions + } + pub fn install_functions( + &self, + mut functions: ResolvedItems, + items: &mut [Function], + ) { + for (i, item) in items.iter_mut().enumerate() { + Self::install_item(item, i, &mut functions); + } + } + + fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) + where + T: ResolveTransparentTypes, + { + if let Some(alias) = item.resolve_transparent_types(library) { + resolved.insert(i, alias); + } + } + fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) + where + T: ResolveTransparentTypes, + { + if let Some(alias) = resolved.remove(&i) { + *item = alias; + } + } +} diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 3354bc29..80569f15 100644 --- a/tests/expectations/transparent.c +++ b/tests/expectations/transparent.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent.compat.c b/tests/expectations/transparent.compat.c index 1ebe9a03..2cf10ed9 100644 --- a/tests/expectations/transparent.compat.c +++ b/tests/expectations/transparent.compat.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index aa6091ca..4459f246 100644 --- a/tests/expectations/transparent.cpp +++ b/tests/expectations/transparent.cpp @@ -8,6 +8,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + using TransparentComplexWrappingStructTuple = DummyStruct; using TransparentPrimitiveWrappingStructTuple = uint32_t; @@ -30,7 +32,21 @@ struct TransparentEmptyStructure { }; -constexpr static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN = 10; +using TransparentPointerWrappingStructure = const uint32_t*; + +using TransparentIntStruct = int32_t; + +using TransparentComplexStruct = DummyStruct; + +using TransparentTransparentStruct = TransparentPrimitiveWrappingStructure; + +using TransparentNonNullStruct = uint32_t*; + +using TransparentOptionNonNullStruct = uint32_t*; + +constexpr static const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN = 10; + +constexpr static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN = 10; extern "C" { @@ -42,6 +58,23 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); } // extern "C" diff --git a/tests/expectations/transparent.pyx b/tests/expectations/transparent.pyx index 839c7742..e300f99a 100644 --- a/tests/expectations/transparent.pyx +++ b/tests/expectations/transparent.pyx @@ -12,6 +12,9 @@ cdef extern from *: ctypedef struct EnumWithAssociatedConstantInImpl: pass + ctypedef struct StructWithAssociatedConstantInImpl: + pass + ctypedef DummyStruct TransparentComplexWrappingStructTuple; ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -31,7 +34,21 @@ cdef extern from *: ctypedef struct TransparentEmptyStructure: pass - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN # = 10 + ctypedef const uint32_t *TransparentPointerWrappingStructure; + + ctypedef int32_t TransparentIntStruct; + + ctypedef DummyStruct TransparentComplexStruct; + + ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + + ctypedef uint32_t *TransparentNonNullStruct; + + ctypedef uint32_t *TransparentOptionNonNullStruct; + + const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -41,4 +58,21 @@ cdef extern from *: TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + + void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_both.c b/tests/expectations/transparent_both.c index df9b8a57..042009d5 100644 --- a/tests/expectations/transparent_both.c +++ b/tests/expectations/transparent_both.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct TransparentEmptyStructure { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_both.compat.c b/tests/expectations/transparent_both.compat.c index 4acd6677..21872104 100644 --- a/tests/expectations/transparent_both.compat.c +++ b/tests/expectations/transparent_both.compat.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct TransparentEmptyStructure { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent_tag.c b/tests/expectations/transparent_tag.c index 2f6dea68..6589eb6b 100644 --- a/tests/expectations/transparent_tag.c +++ b/tests/expectations/transparent_tag.c @@ -7,6 +7,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ struct TransparentEmptyStructure { }; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_tag.compat.c b/tests/expectations/transparent_tag.compat.c index 508d6ad6..2eff06ef 100644 --- a/tests/expectations/transparent_tag.compat.c +++ b/tests/expectations/transparent_tag.compat.c @@ -7,6 +7,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ struct TransparentEmptyStructure { }; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent_tag.pyx b/tests/expectations/transparent_tag.pyx index 15d66f74..204452d6 100644 --- a/tests/expectations/transparent_tag.pyx +++ b/tests/expectations/transparent_tag.pyx @@ -12,6 +12,9 @@ cdef extern from *: cdef struct EnumWithAssociatedConstantInImpl: pass + cdef struct StructWithAssociatedConstantInImpl: + pass + ctypedef DummyStruct TransparentComplexWrappingStructTuple; ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -31,7 +34,21 @@ cdef extern from *: cdef struct TransparentEmptyStructure: pass - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN # = 10 + ctypedef const uint32_t *TransparentPointerWrappingStructure; + + ctypedef int32_t TransparentIntStruct; + + ctypedef DummyStruct TransparentComplexStruct; + + ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + + ctypedef uint32_t *TransparentNonNullStruct; + + ctypedef uint32_t *TransparentOptionNonNullStruct; + + const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -41,4 +58,21 @@ cdef extern from *: TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + + void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_typedef.c b/tests/expectations/transparent_typedef.c new file mode 100644 index 00000000..e0858c11 --- /dev/null +++ b/tests/expectations/transparent_typedef.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct { + const Option_i32 *field; +} Struct_Option_i32; + +typedef Option_i32 Typedef_Option_i32; + +typedef struct { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct { + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct { + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct { + const Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct { + const Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct { + const Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct { + const Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct { + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union { + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +void root_opaque(const Opaque_i32 *o); + +void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + +void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + +void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef.compat.c b/tests/expectations/transparent_typedef.compat.c new file mode 100644 index 00000000..ad2ee828 --- /dev/null +++ b/tests/expectations/transparent_typedef.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct { + const Option_i32 *field; +} Struct_Option_i32; + +typedef Option_i32 Typedef_Option_i32; + +typedef struct { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct { + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct { + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct { + const Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct { + const Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct { + const Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct { + const Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct { + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union { + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const Opaque_i32 *o); + +void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + +void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + +void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef.cpp b/tests/expectations/transparent_typedef.cpp new file mode 100644 index 00000000..a6d98a9f --- /dev/null +++ b/tests/expectations/transparent_typedef.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include + +template +struct Opaque; + +template +struct Option; + +template +struct FullyTransparent1 { + E a; + E *n; + E t; + E (*f)(E a, E *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +template +struct Struct { + const U *field; +}; + +template +using Typedef = U; + +template> +struct NotTransparent1 { + const Option *o; + const Struct *s; + const Typedef *t; + Typedef *(*f)(const Option *o, const Struct *s); + const Option *oi; + const Struct *si; + const Typedef *ti; + Typedef *(*fi)(const Option *oi, const Struct *si); +}; + +template +struct FullyTransparent2 { + E aa; + E *an; + E at; + E *na; + E **nn; + E *nt; + E *on; + E ta; + E *tn; + E tt; + E (*f)(E aa, E *an, E at, E *na, E **nn, E *nt, E *on, E ta, E *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +template> +struct PartlyTransparent2 { + const Option *ao; + const Struct *aS; + const Typedef *at; + Option *const *no; + Struct *const *ns; + Typedef *const *nt; + Typedef **(*f)(const Option *ao, + const Struct *aS, + const Typedef *at, + Option *const *no, + Struct *const *ns); + const Option *aoi; + const Struct *asi; + const Typedef *ati; + Option *const *noi; + Struct *const *nsi; + Typedef *const *nti; + Typedef **(*fi)(const Option *aoi, + const Struct *asi, + const Typedef *ati, + Option *const *noi, + Struct *const *nsi); +}; + +template>> +struct NotTransparent2 { + const Option> *oo; + const Option> *os; + const Struct> *so; + const Struct> *ss; + Struct> *(*f)(const Option> *oo, + const Option> *os, + const Struct> *so); + const Option> *ooi; + const Option> *osi; + const Struct> *soi; + const Struct> *ssi; + Struct> *(*fi)(const Option> *ooi, + const Option> *osi, + const Struct> *soi); +}; + +template +struct FullyTransparentMany { + enum class Tag { + ont, + otn, + ton, + totn, + f, + onti, + otni, + toni, + totni, + fi, + }; + + struct ont_Body { + E *_0; + }; + + struct otn_Body { + E *_0; + }; + + struct ton_Body { + E *_0; + }; + + struct totn_Body { + E *_0; + }; + + struct f_Body { + E *(*_0)(E *ont, E *otn, E *ton); + }; + + struct onti_Body { + int32_t *_0; + }; + + struct otni_Body { + int32_t *_0; + }; + + struct toni_Body { + int32_t *_0; + }; + + struct totni_Body { + int32_t *_0; + }; + + struct fi_Body { + int32_t *(*_0)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + + Tag tag; + union { + ont_Body ont; + otn_Body otn; + ton_Body ton; + totn_Body totn; + f_Body f; + onti_Body onti; + otni_Body otni; + toni_Body toni; + totni_Body totni; + fi_Body fi; + }; +}; + +template> +union PartlyTransparentMany { + const Option *tao; + const Option *toa; + const Option *ota; + const Struct *tas; + const Struct *tsa; + const Struct *sta; + const Option *toat; + const Struct *tsat; + const Option *taoi; + const Option *toai; + const Option *otai; + const Struct *tasi; + const Struct *tsai; + const Struct *stai; + const Option *toati; + const Struct *tsati; +}; + +extern "C" { + +void root_opaque(const Opaque *o); + +void root1(FullyTransparent1 a, NotTransparent1> s); + +void root2(FullyTransparent2 a, + PartlyTransparent2> s, + NotTransparent2>> n); + +void root_many(FullyTransparentMany a, PartlyTransparentMany> b); + +} // extern "C" diff --git a/tests/expectations/transparent_typedef.pyx b/tests/expectations/transparent_typedef.pyx new file mode 100644 index 00000000..e3590f7e --- /dev/null +++ b/tests/expectations/transparent_typedef.pyx @@ -0,0 +1,203 @@ +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 Opaque_i32: + pass + + ctypedef struct Option_Option_Struct_Option_i32: + pass + + ctypedef struct Option_Option_i32: + pass + + ctypedef struct Option_Struct_Option_i32: + pass + + ctypedef struct Option_Struct_Struct_Option_i32: + pass + + ctypedef struct Option_Struct_i32: + pass + + ctypedef struct Option_i32: + pass + + ctypedef struct FullyTransparent1_i32: + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); + + ctypedef struct Struct_Option_i32: + const Option_i32 *field; + + ctypedef Option_i32 Typedef_Option_i32; + + ctypedef struct Struct_i32: + const int32_t *field; + + ctypedef int32_t Typedef_i32; + + ctypedef struct NotTransparent1_Option_i32: + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); + + ctypedef struct FullyTransparent2_i32: + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); + + ctypedef struct PartlyTransparent2_Option_i32: + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); + + ctypedef struct Struct_Option_Struct_Option_i32: + const Option_Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_Option_i32: + const Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_Struct_Option_i32: + const Struct_Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_i32: + const Struct_i32 *field; + + ctypedef struct NotTransparent2_Struct_Option_i32: + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); + + ctypedef enum FullyTransparentMany_____i32_Tag: + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, + + ctypedef struct FullyTransparentMany_____i32: + FullyTransparentMany_____i32_Tag tag; + int32_t **ont; + int32_t **otn; + int32_t **ton; + int32_t **totn; + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + int32_t *onti; + int32_t *otni; + int32_t *toni; + int32_t *totni; + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + + ctypedef union PartlyTransparentMany_Option_i32: + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; + + void root_opaque(const Opaque_i32 *o); + + void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + + void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + + void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_both.c b/tests/expectations/transparent_typedef_both.c new file mode 100644 index 00000000..d40be94f --- /dev/null +++ b/tests/expectations/transparent_typedef_both.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct Struct_Option_i32 { + const struct Option_i32 *field; +} Struct_Option_i32; + +typedef struct Option_i32 Typedef_Option_i32; + +typedef struct Struct_i32 { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct Struct_Struct_i32 { + const struct Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct FullyTransparentMany_____i32 { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_both.compat.c b/tests/expectations/transparent_typedef_both.compat.c new file mode 100644 index 00000000..6d4705b6 --- /dev/null +++ b/tests/expectations/transparent_typedef_both.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct Struct_Option_i32 { + const struct Option_i32 *field; +} Struct_Option_i32; + +typedef struct Option_i32 Typedef_Option_i32; + +typedef struct Struct_i32 { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct Struct_Struct_i32 { + const struct Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct FullyTransparentMany_____i32 { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef_tag.c b/tests/expectations/transparent_typedef_tag.c new file mode 100644 index 00000000..d458f456 --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +struct Opaque_i32; + +struct Option_Option_Struct_Option_i32; + +struct Option_Option_i32; + +struct Option_Struct_Option_i32; + +struct Option_Struct_Struct_Option_i32; + +struct Option_Struct_i32; + +struct Option_i32; + +struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +struct Struct_Option_i32 { + const struct Option_i32 *field; +}; + +typedef struct Option_i32 Typedef_Option_i32; + +struct Struct_i32 { + const int32_t *field; +}; + +typedef int32_t Typedef_i32; + +struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +}; + +struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +}; + +struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +}; + +struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +}; + +struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +}; + +struct Struct_Struct_i32 { + const struct Struct_i32 *field; +}; + +struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +}; + +enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +}; + +struct FullyTransparentMany_____i32 { + enum FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +}; + +union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +}; + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_tag.compat.c b/tests/expectations/transparent_typedef_tag.compat.c new file mode 100644 index 00000000..1a13505e --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +struct Opaque_i32; + +struct Option_Option_Struct_Option_i32; + +struct Option_Option_i32; + +struct Option_Struct_Option_i32; + +struct Option_Struct_Struct_Option_i32; + +struct Option_Struct_i32; + +struct Option_i32; + +struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +struct Struct_Option_i32 { + const struct Option_i32 *field; +}; + +typedef struct Option_i32 Typedef_Option_i32; + +struct Struct_i32 { + const int32_t *field; +}; + +typedef int32_t Typedef_i32; + +struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +}; + +struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +}; + +struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +}; + +struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +}; + +struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +}; + +struct Struct_Struct_i32 { + const struct Struct_i32 *field; +}; + +struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +}; + +enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +}; + +struct FullyTransparentMany_____i32 { + enum FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +}; + +union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef_tag.pyx b/tests/expectations/transparent_typedef_tag.pyx new file mode 100644 index 00000000..87c613ed --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.pyx @@ -0,0 +1,203 @@ +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 Opaque_i32: + pass + + cdef struct Option_Option_Struct_Option_i32: + pass + + cdef struct Option_Option_i32: + pass + + cdef struct Option_Struct_Option_i32: + pass + + cdef struct Option_Struct_Struct_Option_i32: + pass + + cdef struct Option_Struct_i32: + pass + + cdef struct Option_i32: + pass + + cdef struct FullyTransparent1_i32: + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); + + cdef struct Struct_Option_i32: + const Option_i32 *field; + + ctypedef Option_i32 Typedef_Option_i32; + + cdef struct Struct_i32: + const int32_t *field; + + ctypedef int32_t Typedef_i32; + + cdef struct NotTransparent1_Option_i32: + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); + + cdef struct FullyTransparent2_i32: + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); + + cdef struct PartlyTransparent2_Option_i32: + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); + + cdef struct Struct_Option_Struct_Option_i32: + const Option_Struct_Option_i32 *field; + + cdef struct Struct_Struct_Option_i32: + const Struct_Option_i32 *field; + + cdef struct Struct_Struct_Struct_Option_i32: + const Struct_Struct_Option_i32 *field; + + cdef struct Struct_Struct_i32: + const Struct_i32 *field; + + cdef struct NotTransparent2_Struct_Option_i32: + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); + + cdef enum FullyTransparentMany_____i32_Tag: + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, + + cdef struct FullyTransparentMany_____i32: + FullyTransparentMany_____i32_Tag tag; + int32_t **ont; + int32_t **otn; + int32_t **ton; + int32_t **totn; + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + int32_t *onti; + int32_t *otni; + int32_t *toni; + int32_t *totni; + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + + cdef union PartlyTransparentMany_Option_i32: + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; + + void root_opaque(const Opaque_i32 *o); + + void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + + void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + + void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/rust/nonnull.rs b/tests/rust/nonnull.rs index 5e07c35c..4db03171 100644 --- a/tests/rust/nonnull.rs +++ b/tests/rust/nonnull.rs @@ -15,5 +15,8 @@ pub struct Foo { i: Option>>, } +/// cbindgen:transparent-typedef +pub type NonNullPtr = Option>; + #[no_mangle] pub extern "C" fn root(arg: NonNull, foo: *mut Foo, d: NonNull>) { } diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index e35200cf..fb812e33 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -16,6 +16,10 @@ struct TransparentComplexWrappingStructure { only_field: DummyStruct } #[repr(transparent)] struct TransparentPrimitiveWrappingStructure { only_field: u32 } +// Transparent struct wrapping a pointer +#[repr(transparent)] +struct TransparentPointerWrappingStructure { only_field: *const u32 } + // Transparent struct wrapper with a marker wrapping a struct. #[repr(transparent)] struct TransparentComplexWrapper { @@ -53,10 +57,18 @@ impl TransparentPrimitiveWithAssociatedConstants { }; } +struct StructWithAssociatedConstantInImpl { } + +impl StructWithAssociatedConstantInImpl { + pub const STRUCT_TEN: TransparentPrimitiveWrappingStructure = + TransparentPrimitiveWrappingStructure { only_field: 10 }; +} + enum EnumWithAssociatedConstantInImpl { A } impl EnumWithAssociatedConstantInImpl { - pub const TEN: TransparentPrimitiveWrappingStructure = TransparentPrimitiveWrappingStructure { only_field: 10 }; + pub const ENUM_TEN: TransparentPrimitiveWrappingStructure = + TransparentPrimitiveWrappingStructure { only_field: 10 }; } #[no_mangle] @@ -69,5 +81,59 @@ pub extern "C" fn root( f: TransparentPrimitiveWrapper, g: TransparentPrimitiveWithAssociatedConstants, h: TransparentEmptyStructure, - i: EnumWithAssociatedConstantInImpl, + i: TransparentPointerWrappingStructure, + j: StructWithAssociatedConstantInImpl, + k: EnumWithAssociatedConstantInImpl, +) { } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentNonNullPointerWrappingStruct { only_field: NonNull } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentOptionalNonNullPointerWrappingStruct { only_field: Option> } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentWrappingAnotherTransparentStruct { only_field: TransparentPrimitiveWrappingStructure } + +/// cbindgen:transparent-typedef +#[repr(transparent)] +struct ErasedTransparentWrappingTransparentNonNullPointerStruct { only_field: ErasedTransparentNonNullPointerWrappingStruct } + +// Transparent structure wrapping another type +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentStructWrappingAnotherType { only_field: T } + +type TransparentIntStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentComplexStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentTransparentStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentNonNullStruct = ErasedTransparentStructWrappingAnotherType>; +type TransparentOptionNonNullStruct = ErasedTransparentStructWrappingAnotherType>>; + +/// cbindgen:transparent-typedef +type ErasedTransparentIntStruct = ErasedTransparentStructWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentComplexStruct = ErasedTransparentStructWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentOptionNonNullStruct = ErasedTransparentStructWrappingAnotherType>>; + +#[no_mangle] +pub extern "C" fn erased_root( + a: ErasedTransparentNonNullPointerWrappingStruct, + b: ErasedTransparentOptionalNonNullPointerWrappingStruct, + c: ErasedTransparentWrappingAnotherTransparentStruct, + d: ErasedTransparentWrappingTransparentNonNullPointerStruct, + e: ErasedTransparentStructWrappingAnotherType, + f: ErasedTransparentStructWrappingAnotherType, + g: ErasedTransparentStructWrappingAnotherType, + h: ErasedTransparentStructWrappingAnotherType, + i: ErasedTransparentIntStruct, + j: TransparentIntStruct, + k: TransparentComplexStruct, + l: TransparentTransparentStruct, + m: TransparentNonNullStruct, + n: TransparentOptionNonNullStruct, ) { } diff --git a/tests/rust/transparent_typedef.rs b/tests/rust/transparent_typedef.rs new file mode 100644 index 00000000..7987aabf --- /dev/null +++ b/tests/rust/transparent_typedef.rs @@ -0,0 +1,232 @@ +use std::num::NonZero; +use std::ptr::NonNull; + + +/// cbindgen:transparent-typedef +#[repr(transparent)] +pub struct Transparent> { + field: T, + _phantom: std::marker::PhantomData

, +} + +pub type Typedef> = Transparent; + +/// cbindgen:transparent-typedef +pub type Alias> = Transparent; + +pub struct Opaque> { + field: U, +} + +#[no_mangle] +pub extern "C" fn root_opaque(o: &Opaque>>>) {} + +#[repr(C)] +pub struct Struct<'a, U, P = Alias> { + field: &'a U, + _phantom: std::marker::PhantomData

, +} + +#[repr(C)] +pub struct FullyTransparent1> { + a: Alias, + n: NonNull, + t: Transparent, + f: extern "C" fn(a: Alias, n: NonNull) -> Transparent, + + ai: Alias, + ni: NonNull, + ti: Transparent, + fi: extern "C" fn(ai: Alias, ni: NonNull) -> Transparent, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct NotTransparent1<'a, E = Option> { + o: &'a Option, + s: &'a Struct, + t: &'a Typedef, + f: extern "C" fn(o: &Option, s: &Struct) -> *mut Typedef, + + oi: &'a Option, + si: &'a Struct, + ti: &'a Typedef, + fi: extern "C" fn(oi: &Option, si: &Struct) -> *mut Typedef, +} + +#[no_mangle] +pub extern "C" fn root1( + a: FullyTransparent1>, + s: NotTransparent1>) {} + +#[repr(C)] +pub struct FullyTransparent2>> { + aa: Alias>, + an: Alias>, + at: Alias>, + na: NonNull>, + nn: NonNull>, + nt: NonNull>, + on: Option>, + ta: Transparent>, + tn: Transparent>, + tt: Transparent>, + f: extern "C" fn( + aa: Alias>, + an: Alias>, + at: Alias>, + na: NonNull>, + nn: NonNull>, + nt: NonNull>, + on: Option>, + ta: Transparent>, + tn: Transparent>, + ) -> Transparent>, + + aai: Alias>, + ani: Alias>, + ati: Alias>, + nai: NonNull>, + nni: NonNull>, + nti: NonNull>, + oni: Option>, + tai: Transparent>, + tni: Transparent>, + tti: Transparent>, + fi: extern "C" fn( + aai: Alias>, + ani: Alias>, + ati: Alias>, + nai: NonNull>, + nni: NonNull>, + nti: NonNull>, + oni: Option>, + tai: Transparent>, + tni: Transparent>, + ) -> Transparent>, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct PartlyTransparent2<'a, E = Option>> { + ao: &'a Alias>, + aS: &'a Alias>, + at: &'a Alias>, + no: &'a NonNull>, + ns: &'a NonNull>, + nt: &'a NonNull>, + f: extern "C" fn( + ao: &Alias>, + aS: &Alias>, + at: &Alias>, + no: &NonNull>, + ns: &NonNull>, + ) -> *mut NonNull>, + + aoi: &'a Alias>, + asi: &'a Alias>, + ati: &'a Alias>, + noi: &'a NonNull>, + nsi: &'a NonNull>, + nti: &'a NonNull>, + fi: extern "C" fn( + aoi: &Alias>, + asi: &Alias>, + ati: &Alias>, + noi: &NonNull>, + nsi: &NonNull>, + ) -> *mut NonNull>, +} + +// Use references so it still compiles. +#[repr(C)] +pub struct NotTransparent2<'a, E = Option>> { + oo: &'a Option>, + os: &'a Option>, + so: &'a Struct>, + ss: &'a Struct>, + f: extern "C" fn( + oo: &Option>, + os: &Option>, + so: &Struct>, + ) -> *mut Struct>, + + ooi: &'a Option>, + osi: &'a Option>, + soi: &'a Struct>, + ssi: &'a Struct>, + fi: extern "C" fn( + ooi: &Option>, + osi: &Option>, + soi: &Struct>, + ) -> *mut Struct>, +} + +#[no_mangle] +pub extern "C" fn root2( + a: FullyTransparent2>>, + s: PartlyTransparent2>>, + n: NotTransparent2>>) {} + +#[repr(C)] +pub enum FullyTransparentMany>>>>> { + ont(Option>>), + otn(Option>>), + ton(Transparent>>), + + // One erasable quadruple + totn(Transparent>>>), + + f(extern "C" fn( + ont: Option>>, + otn: Option>>, + ton: Transparent>>, + ) -> Transparent>>>), + + onti(Option>>), + otni(Option>>), + toni(Transparent>>), + + // One erasable quadruple + totni(Transparent>>>), + + fi(extern "C" fn( + onti: Option>>, + otni: Option>>, + toni: Transparent>>, + ) -> Transparent>>>), + +} + +#[repr(C)] +pub union PartlyTransparentMany<'a, E = Transparent>>> { + // A few triples + tao: &'a Transparent>>, + toa: &'a Transparent>>, + ota: &'a Option>>, + tas: &'a Transparent>>, + tsa: &'a Transparent>>, + sta: &'a Struct>>, + + // Two quadruples + toat: &'a Transparent>>>, + tsat: &'a Transparent>>>, + + // A few triples + taoi: &'a Transparent>>, + toai: &'a Transparent>>, + otai: &'a Option>>, + tasi: &'a Transparent>>, + tsai: &'a Transparent>>, + stai: &'a Struct>>, + + // Two quadruples + toati: &'a Transparent>>>, + tsati: &'a Transparent>>>, +} + +#[no_mangle] +pub extern "C" fn root_many( + a: FullyTransparentMany>>>, + b: PartlyTransparentMany>>>, +) {}