From 87601a33b36a64ea4e3c570ba0b2257ada52383a Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 17 May 2024 14:54:43 -0700 Subject: [PATCH 1/3] implement transparent typedef feature --- docs.md | 103 +++++++++-- src/bindgen/builder.rs | 2 +- src/bindgen/ir/constant.rs | 16 +- src/bindgen/ir/enumeration.rs | 38 ++-- src/bindgen/ir/function.rs | 23 ++- src/bindgen/ir/generic_path.rs | 67 ++++++- src/bindgen/ir/global.rs | 16 +- src/bindgen/ir/item.rs | 12 +- src/bindgen/ir/opaque.rs | 33 ++++ src/bindgen/ir/structure.rs | 27 ++- src/bindgen/ir/ty.rs | 172 ++++++++++++------ src/bindgen/ir/typedef.rs | 35 +++- src/bindgen/ir/union.rs | 21 ++- src/bindgen/library.rs | 82 +++++---- src/bindgen/parser.rs | 108 +++++++---- tests/expectations/const_transparent.cpp | 4 +- tests/expectations/transparent.c | 37 +++- tests/expectations/transparent.compat.c | 37 +++- tests/expectations/transparent.cpp | 37 +++- tests/expectations/transparent.pyx | 38 +++- tests/expectations/transparent_both.c | 37 +++- tests/expectations/transparent_both.compat.c | 37 +++- tests/expectations/transparent_tag.c | 37 +++- tests/expectations/transparent_tag.compat.c | 37 +++- tests/expectations/transparent_tag.pyx | 38 +++- tests/expectations/transparent_typedef.c | 87 +++++++++ .../expectations/transparent_typedef.compat.c | 95 ++++++++++ tests/expectations/transparent_typedef.cpp | 73 ++++++++ tests/expectations/transparent_typedef.pyx | 82 +++++++++ tests/expectations/transparent_typedef_both.c | 87 +++++++++ .../transparent_typedef_both.compat.c | 95 ++++++++++ tests/expectations/transparent_typedef_tag.c | 87 +++++++++ .../transparent_typedef_tag.compat.c | 95 ++++++++++ .../expectations/transparent_typedef_tag.pyx | 82 +++++++++ tests/rust/const_transparent.rs | 1 + tests/rust/transparent.rs | 70 ++++++- tests/rust/transparent_typedef.rs | 82 +++++++++ 37 files changed, 1817 insertions(+), 213 deletions(-) create mode 100644 tests/expectations/transparent_typedef.c create mode 100644 tests/expectations/transparent_typedef.compat.c create mode 100644 tests/expectations/transparent_typedef.cpp create mode 100644 tests/expectations/transparent_typedef.pyx create mode 100644 tests/expectations/transparent_typedef_both.c create mode 100644 tests/expectations/transparent_typedef_both.compat.c create mode 100644 tests/expectations/transparent_typedef_tag.c create mode 100644 tests/expectations/transparent_typedef_tag.compat.c create mode 100644 tests/expectations/transparent_typedef_tag.pyx create mode 100644 tests/rust/transparent_typedef.rs diff --git a/docs.md b/docs.md index c8ce9f4f2..ad5dcc188 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 d47919b98..a649a0fc0 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 2f1d3bffd..c820b2a41 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -13,8 +13,8 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path, - Struct, ToCondition, Type, + AnnotationSet, Cfg, ConditionWrite, Documentation, GenericArgument, GenericParams, Item, + ItemContainer, Path, Struct, ToCondition, TransparentTypeEraser, Type, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -603,6 +603,18 @@ impl Item for Constant { fn generic_params(&self) -> &GenericParams { GenericParams::empty() } + + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + _generics: &[GenericArgument], + ) { + // 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. + eraser.erase_transparent_types_inplace(library, &mut self.ty, &[]); + } } impl Constant { diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 2e633a7df..f5a0bbeed 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -12,7 +12,7 @@ use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr, - ReprStyle, Struct, ToCondition, Type, + ReprStyle, Struct, ToCondition, TransparentTypeEraser, Type, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -247,12 +247,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); @@ -500,6 +494,30 @@ impl Item for Enum { &self.generic_params } + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + generics: &[GenericArgument], + ) { + let mut skip_inline_tag_field = Self::inline_tag_field(&self.repr); + let generics = self.generic_params.defaulted_generics(generics); + let mappings = self.generic_params.call(self.name(), &generics); + for variant in self.variants.iter_mut() { + if let VariantBody::Body { ref mut body, .. } = variant.body { + for field in body.fields.iter_mut() { + // Ignore the inline Tag field, if any (it's always first) + if skip_inline_tag_field { + debug!("Skipping inline Tag field {:?}", field); + skip_inline_tag_field = false; + } else { + eraser.erase_transparent_types_inplace(library, &mut field.ty, &mappings); + } + } + } + } + } + fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); @@ -1493,10 +1511,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 79adfce94..129f84383 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -9,7 +9,9 @@ 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, GenericPath, Path, TransparentTypeEraser, Type, +}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; @@ -115,13 +117,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 { @@ -150,6 +145,18 @@ impl Function { } } + // NOTE: No `generics` arg because Functions do not support generics and do not `impl Item`. + pub fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + ) { + eraser.erase_transparent_types_inplace(library, &mut self.ret, &[]); + for arg in &mut self.args { + eraser.erase_transparent_types_inplace(library, &mut arg.ty, &[]); + } + } + pub fn rename_for_config(&mut self, config: &Config) { // Rename the types used in arguments let generic_params = Default::default(); diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 4610641ce..8231347f0 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; +use std::collections::HashMap; use std::io::Write; use std::ops::Deref; @@ -8,16 +10,17 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver}; use crate::bindgen::ir::{ConstExpr, Path, Type}; use crate::bindgen::language_backend::LanguageBackend; +use crate::bindgen::library::Library; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::SourceWriter; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum GenericParamType { Type, Const(Type), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct GenericParam { name: Path, ty: GenericParamType, @@ -103,6 +106,24 @@ impl GenericParams { Ok(GenericParams(params)) } + /// If `generics` is empty, create a set of "default" generic arguments, which preserves the + /// existing parameter name. Useful to allow `call` to work when no generics are provided. + pub fn defaulted_generics<'a>( + &self, + generics: &'a [GenericArgument], + ) -> Cow<'a, [GenericArgument]> { + if !self.is_empty() && generics.is_empty() { + Cow::Owned( + self.iter() + .map(|param| Type::Path(GenericPath::new(param.name.clone(), vec![]))) + .map(GenericArgument::Type) + .collect(), + ) + } else { + Cow::Borrowed(generics) + } + } + /// Associate each parameter with an argument. pub fn call<'out>( &'out self, @@ -234,6 +255,48 @@ impl GenericArgument { } } +/// Helper for erasing transparent types, which memoizes already-seen types to avoid repeated work. +#[derive(Default)] +pub struct TransparentTypeEraser { + // Remember paths we've already visited, so we don't repeat unnecessary work. + // TODO: how to handle recursive types such as `struct Foo { next: Box }`? + known_types: HashMap>, +} + +impl TransparentTypeEraser { + pub fn erase_transparent_types_inplace( + &mut self, + library: &Library, + target: &mut Type, + mappings: &[(&Path, &GenericArgument)], + ) { + if let Some(erased_type) = self.erase_transparent_types(library, target, mappings) { + *target = erased_type; + } + } + + #[must_use] + pub fn erase_transparent_types( + &mut self, + library: &Library, + target: &Type, + mappings: &[(&Path, &GenericArgument)], + ) -> Option { + let known_type = self.known_types.get(target); + let unknown_type = known_type.is_none(); + let erased_type = if let Some(ty) = known_type { + ty.clone() + } else { + target.erase_transparent_types(library, mappings, self) + }; + if unknown_type { + debug!("Caching erasure of {:?} as {:?}", target, erased_type); + self.known_types.insert(target.clone(), erased_type.clone()); + } + erased_type + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct GenericPath { path: Path, diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 7816a294b..3d825eaa2 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -6,7 +6,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericParams, Item, ItemContainer, Path, Type, + AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + TransparentTypeEraser, Type, }; use crate::bindgen::library::Library; @@ -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 { @@ -109,6 +106,15 @@ impl Item for Static { GenericParams::empty() } + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + _generics: &[GenericArgument], + ) { + eraser.erase_transparent_types_inplace(library, &mut self.ty, &[]); + } + fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { self.ty.add_dependencies(library, out); } diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 03e1c153a..12ebfeb2f 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -10,7 +10,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Enum, GenericArgument, GenericParams, OpaqueItem, - Path, Static, Struct, Typedef, Union, + Path, Static, Struct, TransparentTypeEraser, Typedef, Union, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -39,6 +39,16 @@ pub trait Item { } fn generic_params(&self) -> &GenericParams; + /// Recursively erases any transparent types this item references. Type erasure impacts typedefs + /// and/or `#[repr(transparent)]` types annotated with `cbindgen:transparent-typedef`. It also + /// impacts certain built-in types (such as `Box`, `Option`, `Pin`, and `NonNull`). + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + generics: &[GenericArgument], + ); + fn is_generic(&self) -> bool { !self.generic_params().is_empty() } diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4527e3ca8..7db1918d7 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -7,6 +7,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + TransparentTypeEraser, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -55,6 +56,29 @@ impl OpaqueItem { documentation, } } + + // Most transparent well-known types are registered as transparent typedefs at parsing + // time. Some well-known generic types can be transparent, but with type-specific semantics that + // cannot be captured by a simple transparent typedef. The parser registers them as opaque items + // to be handled here. + pub fn as_transparent_alias(&self, generics: &[GenericArgument]) -> Option { + if let Some(GenericArgument::Type(ref ty)) = generics.first() { + match self.name() { + "NonNull" => { + return Some(Type::Ptr { + ty: Box::new(ty.clone()), + is_const: false, + is_nullable: false, + is_ref: false, + }) + } + "NonZero" => return ty.make_zeroable(false), + "Option" => return ty.make_nullable().or_else(|| ty.make_zeroable(true)), + _ => {} + } + } + None + } } impl Item for OpaqueItem { @@ -94,6 +118,15 @@ impl Item for OpaqueItem { &self.generic_params } + fn erase_transparent_types_inplace( + &mut self, + _library: &Library, + _erased: &mut TransparentTypeEraser, + _generics: &[GenericArgument], + ) { + // Nothing to do here, because we don't reference any types. + } + fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 9b33a15c7..602c8a934 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, + ItemContainer, Path, Repr, ReprAlign, ReprStyle, TransparentTypeEraser, Type, Typedef, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -160,12 +160,6 @@ 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() { @@ -174,6 +168,12 @@ impl Struct { } } + // Transparent structs become typedefs, so try converting to typedef and recurse on that. + pub fn as_transparent_alias(&self, generics: &[GenericArgument]) -> Option { + self.as_typedef() + .and_then(|t| t.as_transparent_alias(generics)) + } + 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. @@ -312,6 +312,19 @@ impl Item for Struct { &self.generic_params } + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + generics: &[GenericArgument], + ) { + let generics = self.generic_params.defaulted_generics(generics); + let mappings = self.generic_params.call(self.name(), &generics); + for field in &mut self.fields { + eraser.erase_transparent_types_inplace(library, &mut field.ty, &mappings); + } + } + fn rename_for_config(&mut self, config: &Config) { // Rename the name of the struct if !(self.has_tag_field && config.language == Language::Cxx) { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 4a41d4cf3..c396eeda6 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -2,14 +2,14 @@ * 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 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::ir::{ + GenericArgument, GenericParams, GenericPath, ItemContainer, Path, TransparentTypeEraser, +}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::utilities::IterHelpers; @@ -519,59 +519,121 @@ 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, - }), - "Cell" => Some(generic.into_owned()), - "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => { - Some(generic.into_owned()) + #[must_use] + pub fn erase_transparent_types( + &self, + library: &Library, + mappings: &[(&Path, &GenericArgument)], + eraser: &mut TransparentTypeEraser, + ) -> Option { + match *self { + Type::Ptr { + ref ty, + is_const, + is_nullable, + is_ref, + } => { + if let Some(erased_type) = eraser.erase_transparent_types(library, ty, mappings) { + return Some(Type::Ptr { + ty: Box::new(erased_type), + is_const, + is_nullable, + is_ref, + }); + } + } + Type::Path(ref path) => { + if let Some(mut items) = library.get_items(path.path()) { + if let Some(item) = items.first_mut() { + // First, erase the generic args themselves. This is nice for most Item + // types, but crucial for `OpaqueItem` that would otherwise miss out. + let mut did_erase_generics = false; + let generics: Vec<_> = path + .generics() + .iter() + .map(|g| match g { + GenericArgument::Type(ty) => { + let erased_ty = + eraser.erase_transparent_types(library, ty, mappings); + if erased_ty.is_some() { + did_erase_generics = true; + }; + GenericArgument::Type(erased_ty.unwrap_or_else(|| ty.clone())) + } + other => other.clone(), + }) + .collect(); + + // Replace transparent items with their underlying type and erase it. + let aliased_ty = match item { + ItemContainer::OpaqueItem(o) => o.as_transparent_alias(&generics), + ItemContainer::Typedef(t) => t.as_transparent_alias(&generics), + ItemContainer::Struct(s) => s.as_transparent_alias(&generics), + _ => None, + }; + if let Some(mut ty) = aliased_ty { + eraser.erase_transparent_types_inplace(library, &mut ty, mappings); + return Some(ty); + } else if did_erase_generics { + // The type was not transparent, but some of its generics were erased. + let path = GenericPath::new(path.path().clone(), generics); + return Some(Type::Path(path)); + } + } + } else { + warn!( + "Can't find {}. This usually means that this type was incompatible or \ + not found.", + path.path() + ); + } + } + Type::Primitive(..) => {} // cannot simplify further + Type::Array(ref ty, ref constexpr) => { + if let Some(erased_ty) = eraser.erase_transparent_types(library, ty, mappings) { + return Some(Type::Array(Box::new(erased_ty), constexpr.clone())); + } + } + Type::FuncPtr { + ref ret, + ref args, + is_nullable, + never_return, + } => { + // Predict that ret+args will all be erased, but decrement the count whenever we're + // wrong. If the count drops to 0, then type erasure was a no-op after all. + let mut num_erased = 1 + args.len(); + let erased_ret = eraser + .erase_transparent_types(library, ret, mappings) + .unwrap_or_else(|| { + num_erased -= 1; + ret.as_ref().clone() + }); + + let erased_args = args + .iter() + .map(|(name, ty)| { + let erased_ty = eraser + .erase_transparent_types(library, ty, mappings) + .unwrap_or_else(|| { + num_erased -= 1; + ty.clone() + }); + (name.clone(), erased_ty) + }) + .collect(); + + if num_erased > 0 { + return Some(Type::FuncPtr { + ret: Box::new(erased_ret), + args: erased_args, + is_nullable, + never_return, + }); + } } - _ => 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; } + None } pub fn replace_self_with(&mut self, self_ty: &Path) { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e775a4e80..580cea33f 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, - Path, Struct, Type, + Path, Struct, TransparentTypeEraser, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -30,6 +30,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 +69,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 +101,21 @@ impl Typedef { } } + /// Returns the aliased type if this typedef is transparent, else None. + pub fn as_transparent_alias(&self, generics: &[GenericArgument]) -> Option { + if self + .annotations + .bool(Self::TRANSPARENT_TYPEDEF) + .unwrap_or(false) + { + let generics = self.generic_params.defaulted_generics(generics); + let mappings = self.generic_params.call(self.name(), &generics); + Some(self.aliased.specialize(&mappings)) + } else { + None + } + } + 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. @@ -156,6 +170,17 @@ impl Item for Typedef { &self.generic_params } + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + generics: &[GenericArgument], + ) { + let generics = self.generic_params.defaulted_generics(generics); + let mappings = self.generic_params.call(self.name(), &generics); + eraser.erase_transparent_types_inplace(library, &mut self.aliased, &mappings); + } + fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); self.aliased.rename_for_config(config, &self.generic_params); diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 410e21a27..982b3168f 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -9,7 +9,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, - Path, Repr, ReprAlign, ReprStyle, + Path, Repr, ReprAlign, ReprStyle, TransparentTypeEraser, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -94,12 +94,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. @@ -162,6 +156,19 @@ impl Item for Union { &self.generic_params } + fn erase_transparent_types_inplace( + &mut self, + library: &Library, + eraser: &mut TransparentTypeEraser, + generics: &[GenericArgument], + ) { + let generics = self.generic_params.defaulted_generics(generics); + let mappings = self.generic_params.call(self.name(), &generics); + for field in &mut self.fields { + eraser.erase_transparent_types_inplace(library, &mut field.ty, &mappings); + } + } + fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); for field in &mut self.fields { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f9..375dc7e70 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -10,7 +10,9 @@ use crate::bindgen::config::{Config, Language, SortKey}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::error::Error; -use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; +use crate::bindgen::ir::{ + Constant, Enum, Function, Item, ItemContainer, ItemMap, TransparentTypeEraser, +}; use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::ItemType; @@ -61,8 +63,9 @@ impl Library { } pub fn generate(mut self) -> Result { + let mut eraser = TransparentTypeEraser::default(); + self.erase_transparent_types(&mut eraser); 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)), @@ -70,7 +73,7 @@ impl Library { } if self.config.language != Language::Cxx { - self.instantiate_monomorphs(); + self.instantiate_monomorphs(&mut eraser); } self.remove_excluded(); if self.config.language == Language::C { @@ -172,6 +175,39 @@ impl Library { &self.config } + fn erase_transparent_types_for_items( + &self, + eraser: &mut TransparentTypeEraser, + items: &ItemMap, + ) -> ItemMap { + // NOTE: Because `items` is actually a shared reference to `self`, we cannot take it as + // mutable. We also cannot `drain` or `take` it first, because then the items would be + // unavailable for lookup during the type erasure process. So we mutate a clone, and let the + // caller assign the result back after these shared references have died. + let mut items = items.clone(); + items.for_all_items_mut(|item| { + item.erase_transparent_types_inplace(self, eraser, &[]); + }); + items + } + + fn erase_transparent_types(&mut self, eraser: &mut TransparentTypeEraser) { + self.constants = self.erase_transparent_types_for_items(eraser, &self.constants); + self.globals = self.erase_transparent_types_for_items(eraser, &self.globals); + self.enums = self.erase_transparent_types_for_items(eraser, &self.enums); + self.structs = self.erase_transparent_types_for_items(eraser, &self.structs); + self.unions = self.erase_transparent_types_for_items(eraser, &self.unions); + self.opaque_items = self.erase_transparent_types_for_items(eraser, &self.opaque_items); + self.typedefs = self.erase_transparent_types_for_items(eraser, &self.typedefs); + + // Functions do not `impl Item` and are not stored in an `ItemMap`, so do them manually. + let mut functions = self.functions.clone(); + for f in &mut functions { + f.erase_transparent_types_inplace(self, eraser); + } + self.functions = functions; + } + fn remove_excluded(&mut self) { let config = &self.config; // FIXME: interpret `config.export.exclude` as `Path`s. @@ -367,30 +403,7 @@ 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) { + fn instantiate_monomorphs(&mut self, eraser: &mut TransparentTypeEraser) { // Collect a list of monomorphs let mut monomorphs = Monomorphs::default(); @@ -411,19 +424,24 @@ impl Library { } // Insert the monomorphs into self - for monomorph in monomorphs.drain_structs() { + for mut monomorph in monomorphs.drain_structs() { + monomorph.erase_transparent_types_inplace(self, eraser, &[]); self.structs.try_insert(monomorph); } - for monomorph in monomorphs.drain_unions() { + for mut monomorph in monomorphs.drain_unions() { + monomorph.erase_transparent_types_inplace(self, eraser, &[]); self.unions.try_insert(monomorph); } - for monomorph in monomorphs.drain_opaques() { + for mut monomorph in monomorphs.drain_opaques() { + monomorph.erase_transparent_types_inplace(self, eraser, &[]); self.opaque_items.try_insert(monomorph); } - for monomorph in monomorphs.drain_typedefs() { + for mut monomorph in monomorphs.drain_typedefs() { + monomorph.erase_transparent_types_inplace(self, eraser, &[]); self.typedefs.try_insert(monomorph); } - for monomorph in monomorphs.drain_enums() { + for mut monomorph in monomorphs.drain_enums() { + monomorph.erase_transparent_types_inplace(self, eraser, &[]); self.enums.try_insert(monomorph); } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index eb2ef2dc0..edd1f35d0 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,76 @@ 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: &[&str]) -> Vec { + param_names + .iter() + .map(|name| GenericParam::new_type_param(name)) + .collect() + } + + fn add_opaque(&mut self, path: &str, generic_param_names: &[&str]) { + let path = Path::new(path); + self.opaque_items.try_insert(OpaqueItem::new( + path, + GenericParams(Self::create_generic_params(generic_param_names)), + None, + AnnotationSet::new(), + Documentation::none(), + )); + } + + fn add_transparent_typedef(&mut self, name: &str, aliased: Type, generics: &[&str]) { + let mut annotations = AnnotationSet::new(); + annotations.add_default(Typedef::TRANSPARENT_TYPEDEF, AnnotationValue::Bool(true)); + self.typedefs.try_insert(Typedef::new( + Path::new(name), + GenericParams(Self::create_generic_params(generics)), + aliased, + None, + annotations, + Documentation::none(), + )); + } + + pub fn add_std_types(&mut self, language: Language) { + // Well-known always-opaque types + self.add_opaque("Arc", &["T"]); + self.add_opaque("BTreeMap", &["K", "V"]); + self.add_opaque("BTreeSet", &["T"]); + self.add_opaque("HashMap", &["K", "V", "Hasher"]); + self.add_opaque("HashSet", &["T"]); + self.add_opaque("LinkedList", &["T"]); + self.add_opaque("Rc", &["T"]); + self.add_opaque("RefCell", &["T"]); + self.add_opaque("Result", &["T", "E"]); + self.add_opaque("String", &[]); + self.add_opaque("Vec", &["T"]); + self.add_opaque("VecDeque", &["T"]); + + // Well-known types with special erasure semantics (see [Type::erase_transparent_types]). + self.add_opaque("NonNull", &["T"]); + self.add_opaque("NonZero", &["T"]); + self.add_opaque("Option", &["T"]); + + // Well-known types whose treatment depends on the output language + let tpath = Type::Path(GenericPath::new(Path::new("T"), vec![])); + if language == Language::Cxx { + self.add_opaque("Box", &["T"]); + self.add_opaque("ManuallyDrop", &["T"]); + self.add_opaque("MaybeUninit", &["T"]); + self.add_opaque("Pin", &["T"]); + } else { + // Box acts like NonNull in C + let generics = vec![GenericArgument::Type(tpath.clone())]; + let alias = Type::Path(GenericPath::new(Path::new("NonNull"), generics)); + self.add_transparent_typedef("Box", alias, &["T"]); + self.add_transparent_typedef("ManuallyDrop", tpath.clone(), &["T"]); + self.add_transparent_typedef("MaybeUninit", tpath.clone(), &["T"]); + self.add_transparent_typedef("Pin", tpath.clone(), &["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"]); + // Well-known and always-erased types + self.add_transparent_typedef("Cell", tpath.clone(), &["T"]); } pub fn extend_with(&mut self, other: &Parse) { diff --git a/tests/expectations/const_transparent.cpp b/tests/expectations/const_transparent.cpp index 963ee7fed..285fd8eaf 100644 --- a/tests/expectations/const_transparent.cpp +++ b/tests/expectations/const_transparent.cpp @@ -15,12 +15,12 @@ constexpr static const Wrapper TransparentStruct_ASSOC_STRUCT using TransparentTupleStruct = uint8_t; template -using TransparentStructWithErasedField = Wrapper; +using TransparentStructWithErasedField = T; constexpr static const TransparentStruct STRUCT_FOO = 4; constexpr static const TransparentTupleStruct STRUCT_BAR = 5; -constexpr static const Wrapper STRUCT_BAZ = 6; +constexpr static const TransparentStruct STRUCT_BAZ = 6; constexpr static const TransparentStructWithErasedField COMPLEX = 7; diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 3354bc294..80569f155 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 1ebe9a037..2cf10ed9e 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 aa6091ca6..4459f2463 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 839c77427..e300f99ae 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 df9b8a57d..042009d51 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 4acd6677d..21872104d 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 2f6dea68e..6589eb6bc 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 508d6ad67..2eff06ef0 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 15d66f74c..204452d64 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 000000000..331d48da8 --- /dev/null +++ b/tests/expectations/transparent_typedef.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_i64 Option_i64; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; +} AlwaysErased1_i32; + +typedef struct { + int16_t *const *o; +} SometimesErased1_____i16; + +typedef struct { + const int32_t *o; +} SometimesErased1_i32; + +typedef struct { + const Option_i64 *o; +} SometimesErased1_i64; + +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; +} AlwaysErased2_i32; + +typedef struct { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +} SometimesErased2_____i16; + +typedef struct { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +} SometimesErased2_i32; + +typedef struct { + const Option_i64 *ao; + Option_i64 *const *no; + const Option_i64 *oa; + const Option_i64 *ot; + const Option_i64 *to; +} SometimesErased2_i64; + +typedef struct { + const Option_Option_i32 *oo; +} NeverErased2_i32; + +typedef struct { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +} AlwaysErasedMany_i32; + +void root1(AlwaysErased1_i32 a, + SometimesErased1_____i16 sn, + SometimesErased1_i32 sz, + SometimesErased1_i64 si); + +void root2(AlwaysErased2_i32 a, + SometimesErased2_____i16 sn, + SometimesErased2_i32 sz, + SometimesErased2_i64 si, + NeverErased2_i32 n); + +void root_many(AlwaysErasedMany_i32 a); diff --git a/tests/expectations/transparent_typedef.compat.c b/tests/expectations/transparent_typedef.compat.c new file mode 100644 index 000000000..0cbcbfd76 --- /dev/null +++ b/tests/expectations/transparent_typedef.compat.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_i64 Option_i64; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; +} AlwaysErased1_i32; + +typedef struct { + int16_t *const *o; +} SometimesErased1_____i16; + +typedef struct { + const int32_t *o; +} SometimesErased1_i32; + +typedef struct { + const Option_i64 *o; +} SometimesErased1_i64; + +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; +} AlwaysErased2_i32; + +typedef struct { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +} SometimesErased2_____i16; + +typedef struct { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +} SometimesErased2_i32; + +typedef struct { + const Option_i64 *ao; + Option_i64 *const *no; + const Option_i64 *oa; + const Option_i64 *ot; + const Option_i64 *to; +} SometimesErased2_i64; + +typedef struct { + const Option_Option_i32 *oo; +} NeverErased2_i32; + +typedef struct { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +} AlwaysErasedMany_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root1(AlwaysErased1_i32 a, + SometimesErased1_____i16 sn, + SometimesErased1_i32 sz, + SometimesErased1_i64 si); + +void root2(AlwaysErased2_i32 a, + SometimesErased2_____i16 sn, + SometimesErased2_i32 sz, + SometimesErased2_i64 si, + NeverErased2_i32 n); + +void root_many(AlwaysErasedMany_i32 a); + +#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 000000000..17b2628d9 --- /dev/null +++ b/tests/expectations/transparent_typedef.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +template +struct Option; + +template +struct AlwaysErased1 { + T a; + T *n; + T t; +}; + +template +struct SometimesErased1 { + const Option *o; +}; + +template +struct AlwaysErased2 { + T aa; + T *an; + T at; + T *na; + T **nn; + T *nt; + T *on; + T ta; + T *tn; + T tt; +}; + +template +struct SometimesErased2 { + const Option *ao; + Option *const *no; + const Option *oa; + const Option *ot; + const Option *to; +}; + +template +struct NeverErased2 { + const Option> *oo; +}; + +template +struct AlwaysErasedMany { + T *tont; + T *otnt; + T *totn; + T *totnt; +}; + +extern "C" { + +void root1(AlwaysErased1 a, + SometimesErased1 sn, + SometimesErased1 sz, + SometimesErased1 si); + +void root2(AlwaysErased2 a, + SometimesErased2 sn, + SometimesErased2 sz, + SometimesErased2 si, + NeverErased2 n); + +void root_many(AlwaysErasedMany a); + +} // extern "C" diff --git a/tests/expectations/transparent_typedef.pyx b/tests/expectations/transparent_typedef.pyx new file mode 100644 index 000000000..ea11f12b6 --- /dev/null +++ b/tests/expectations/transparent_typedef.pyx @@ -0,0 +1,82 @@ +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 Option_Option_i32: + pass + + ctypedef struct Option_i64: + pass + + ctypedef struct AlwaysErased1_i32: + int32_t a; + int32_t *n; + int32_t t; + + ctypedef struct SometimesErased1_____i16: + int16_t *const *o; + + ctypedef struct SometimesErased1_i32: + const int32_t *o; + + ctypedef struct SometimesErased1_i64: + const Option_i64 *o; + + ctypedef struct AlwaysErased2_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; + + ctypedef struct SometimesErased2_____i16: + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; + + ctypedef struct SometimesErased2_i32: + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; + + ctypedef struct SometimesErased2_i64: + const Option_i64 *ao; + Option_i64 *const *no; + const Option_i64 *oa; + const Option_i64 *ot; + const Option_i64 *to; + + ctypedef struct NeverErased2_i32: + const Option_Option_i32 *oo; + + ctypedef struct AlwaysErasedMany_i32: + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; + + void root1(AlwaysErased1_i32 a, + SometimesErased1_____i16 sn, + SometimesErased1_i32 sz, + SometimesErased1_i64 si); + + void root2(AlwaysErased2_i32 a, + SometimesErased2_____i16 sn, + SometimesErased2_i32 sz, + SometimesErased2_i64 si, + NeverErased2_i32 n); + + void root_many(AlwaysErasedMany_i32 a); diff --git a/tests/expectations/transparent_typedef_both.c b/tests/expectations/transparent_typedef_both.c new file mode 100644 index 000000000..40b693ba1 --- /dev/null +++ b/tests/expectations/transparent_typedef_both.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_i64 Option_i64; + +typedef struct AlwaysErased1_i32 { + int32_t a; + int32_t *n; + int32_t t; +} AlwaysErased1_i32; + +typedef struct SometimesErased1_____i16 { + int16_t *const *o; +} SometimesErased1_____i16; + +typedef struct SometimesErased1_i32 { + const int32_t *o; +} SometimesErased1_i32; + +typedef struct SometimesErased1_i64 { + const struct Option_i64 *o; +} SometimesErased1_i64; + +typedef struct AlwaysErased2_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; +} AlwaysErased2_i32; + +typedef struct SometimesErased2_____i16 { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +} SometimesErased2_____i16; + +typedef struct SometimesErased2_i32 { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +} SometimesErased2_i32; + +typedef struct SometimesErased2_i64 { + const struct Option_i64 *ao; + struct Option_i64 *const *no; + const struct Option_i64 *oa; + const struct Option_i64 *ot; + const struct Option_i64 *to; +} SometimesErased2_i64; + +typedef struct NeverErased2_i32 { + const struct Option_Option_i32 *oo; +} NeverErased2_i32; + +typedef struct AlwaysErasedMany_i32 { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +} AlwaysErasedMany_i32; + +void root1(struct AlwaysErased1_i32 a, + struct SometimesErased1_____i16 sn, + struct SometimesErased1_i32 sz, + struct SometimesErased1_i64 si); + +void root2(struct AlwaysErased2_i32 a, + struct SometimesErased2_____i16 sn, + struct SometimesErased2_i32 sz, + struct SometimesErased2_i64 si, + struct NeverErased2_i32 n); + +void root_many(struct AlwaysErasedMany_i32 a); diff --git a/tests/expectations/transparent_typedef_both.compat.c b/tests/expectations/transparent_typedef_both.compat.c new file mode 100644 index 000000000..7d09175c8 --- /dev/null +++ b/tests/expectations/transparent_typedef_both.compat.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_i64 Option_i64; + +typedef struct AlwaysErased1_i32 { + int32_t a; + int32_t *n; + int32_t t; +} AlwaysErased1_i32; + +typedef struct SometimesErased1_____i16 { + int16_t *const *o; +} SometimesErased1_____i16; + +typedef struct SometimesErased1_i32 { + const int32_t *o; +} SometimesErased1_i32; + +typedef struct SometimesErased1_i64 { + const struct Option_i64 *o; +} SometimesErased1_i64; + +typedef struct AlwaysErased2_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; +} AlwaysErased2_i32; + +typedef struct SometimesErased2_____i16 { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +} SometimesErased2_____i16; + +typedef struct SometimesErased2_i32 { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +} SometimesErased2_i32; + +typedef struct SometimesErased2_i64 { + const struct Option_i64 *ao; + struct Option_i64 *const *no; + const struct Option_i64 *oa; + const struct Option_i64 *ot; + const struct Option_i64 *to; +} SometimesErased2_i64; + +typedef struct NeverErased2_i32 { + const struct Option_Option_i32 *oo; +} NeverErased2_i32; + +typedef struct AlwaysErasedMany_i32 { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +} AlwaysErasedMany_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root1(struct AlwaysErased1_i32 a, + struct SometimesErased1_____i16 sn, + struct SometimesErased1_i32 sz, + struct SometimesErased1_i64 si); + +void root2(struct AlwaysErased2_i32 a, + struct SometimesErased2_____i16 sn, + struct SometimesErased2_i32 sz, + struct SometimesErased2_i64 si, + struct NeverErased2_i32 n); + +void root_many(struct AlwaysErasedMany_i32 a); + +#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 000000000..92ba5bf88 --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +struct Option_Option_i32; + +struct Option_i64; + +struct AlwaysErased1_i32 { + int32_t a; + int32_t *n; + int32_t t; +}; + +struct SometimesErased1_____i16 { + int16_t *const *o; +}; + +struct SometimesErased1_i32 { + const int32_t *o; +}; + +struct SometimesErased1_i64 { + const struct Option_i64 *o; +}; + +struct AlwaysErased2_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; +}; + +struct SometimesErased2_____i16 { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +}; + +struct SometimesErased2_i32 { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +}; + +struct SometimesErased2_i64 { + const struct Option_i64 *ao; + struct Option_i64 *const *no; + const struct Option_i64 *oa; + const struct Option_i64 *ot; + const struct Option_i64 *to; +}; + +struct NeverErased2_i32 { + const struct Option_Option_i32 *oo; +}; + +struct AlwaysErasedMany_i32 { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +}; + +void root1(struct AlwaysErased1_i32 a, + struct SometimesErased1_____i16 sn, + struct SometimesErased1_i32 sz, + struct SometimesErased1_i64 si); + +void root2(struct AlwaysErased2_i32 a, + struct SometimesErased2_____i16 sn, + struct SometimesErased2_i32 sz, + struct SometimesErased2_i64 si, + struct NeverErased2_i32 n); + +void root_many(struct AlwaysErasedMany_i32 a); diff --git a/tests/expectations/transparent_typedef_tag.compat.c b/tests/expectations/transparent_typedef_tag.compat.c new file mode 100644 index 000000000..952651170 --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.compat.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +struct Option_Option_i32; + +struct Option_i64; + +struct AlwaysErased1_i32 { + int32_t a; + int32_t *n; + int32_t t; +}; + +struct SometimesErased1_____i16 { + int16_t *const *o; +}; + +struct SometimesErased1_i32 { + const int32_t *o; +}; + +struct SometimesErased1_i64 { + const struct Option_i64 *o; +}; + +struct AlwaysErased2_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; +}; + +struct SometimesErased2_____i16 { + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; +}; + +struct SometimesErased2_i32 { + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; +}; + +struct SometimesErased2_i64 { + const struct Option_i64 *ao; + struct Option_i64 *const *no; + const struct Option_i64 *oa; + const struct Option_i64 *ot; + const struct Option_i64 *to; +}; + +struct NeverErased2_i32 { + const struct Option_Option_i32 *oo; +}; + +struct AlwaysErasedMany_i32 { + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root1(struct AlwaysErased1_i32 a, + struct SometimesErased1_____i16 sn, + struct SometimesErased1_i32 sz, + struct SometimesErased1_i64 si); + +void root2(struct AlwaysErased2_i32 a, + struct SometimesErased2_____i16 sn, + struct SometimesErased2_i32 sz, + struct SometimesErased2_i64 si, + struct NeverErased2_i32 n); + +void root_many(struct AlwaysErasedMany_i32 a); + +#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 000000000..180322949 --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.pyx @@ -0,0 +1,82 @@ +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 Option_Option_i32: + pass + + cdef struct Option_i64: + pass + + cdef struct AlwaysErased1_i32: + int32_t a; + int32_t *n; + int32_t t; + + cdef struct SometimesErased1_____i16: + int16_t *const *o; + + cdef struct SometimesErased1_i32: + const int32_t *o; + + cdef struct SometimesErased1_i64: + const Option_i64 *o; + + cdef struct AlwaysErased2_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; + + cdef struct SometimesErased2_____i16: + int16_t *const *ao; + int16_t **const *no; + int16_t *const *oa; + int16_t *const *ot; + int16_t *const *to; + + cdef struct SometimesErased2_i32: + const int32_t *ao; + int32_t *const *no; + const int32_t *oa; + const int32_t *ot; + const int32_t *to; + + cdef struct SometimesErased2_i64: + const Option_i64 *ao; + Option_i64 *const *no; + const Option_i64 *oa; + const Option_i64 *ot; + const Option_i64 *to; + + cdef struct NeverErased2_i32: + const Option_Option_i32 *oo; + + cdef struct AlwaysErasedMany_i32: + int32_t *tont; + int32_t *otnt; + int32_t *totn; + int32_t *totnt; + + void root1(AlwaysErased1_i32 a, + SometimesErased1_____i16 sn, + SometimesErased1_i32 sz, + SometimesErased1_i64 si); + + void root2(AlwaysErased2_i32 a, + SometimesErased2_____i16 sn, + SometimesErased2_i32 sz, + SometimesErased2_i64 si, + NeverErased2_i32 n); + + void root_many(AlwaysErasedMany_i32 a); diff --git a/tests/rust/const_transparent.rs b/tests/rust/const_transparent.rs index 83b9dacbe..1e2e81c9b 100644 --- a/tests/rust/const_transparent.rs +++ b/tests/rust/const_transparent.rs @@ -12,6 +12,7 @@ impl TransparentStruct { #[repr(transparent)] struct TransparentTupleStruct(u8); +/// cbindgen:transparent-typedef #[repr(transparent)] struct Wrapper { field: T } diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index e35200cf1..fb812e334 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 000000000..efd07cfa7 --- /dev/null +++ b/tests/rust/transparent_typedef.rs @@ -0,0 +1,82 @@ +/// cbindgen:transparent-typedef +#[repr(transparent)] +pub struct Transparent { + field: T, + _phantom: std::marker::PhantomData

, +} + +/// cbindgen:transparent-typedef +pub type Alias = Transparent; + + +#[repr(C)] +pub struct AlwaysErased1 { + a: Alias, + n: NonNull, + t: Transparent, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct SometimesErased1 { + o: &Option, +} + +#[no_mangle] +pub extern "C" fn root1( + a: AlwaysErased1, + sn: SometimesErased1>, + sz: SometimesErased1>, + si: SometimesErased1) {} + +#[repr(C)] +pub struct AlwaysErased2 { + aa: Alias>, + an: Alias>, + at: Alias>, + na: NonNull>, + nn: NonNull>, + nt: NonNull>, + on: Option>, + ta: Transparent>, + tn: Transparent>, + tt: Transparent>, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct SometimesErased2 { + ao: &Alias>, + no: &NonNull>, + oa: &Option>, + ot: &Option>, + to: &Transparent>, +} + +// Use references so it still compiles. +#[repr(C)] +pub struct NeverErased2 { + oo: &Option>, +} + +#[no_mangle] +pub extern "C" fn root2( + a: AlwaysErased2, + sn: SometimesErased2>, + sz: SometimesErased2>, + si: SometimesErased2, + n: NeverErased2) {} + +#[repr(C)] +pub struct AlwaysErasedMany { + // A few erasable quadruplets + tont: Transparent>>>, + otnt: Option>>>, + totn: Transparent>>>, + + // One erasable quintuplet + totnt: Transparent>>>>, +} + +#[no_mangle] +pub extern "C" fn root_many(a: AlwaysErasedMany) {} From 42ae2fe652316507f428fb400a9184b83cb7e16d Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Mon, 12 Aug 2024 15:10:13 -0700 Subject: [PATCH 2/3] address review: simplify function type erasure logic --- src/bindgen/ir/ty.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index c396eeda6..78690ecaa 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -600,30 +600,24 @@ impl Type { is_nullable, never_return, } => { - // Predict that ret+args will all be erased, but decrement the count whenever we're - // wrong. If the count drops to 0, then type erasure was a no-op after all. - let mut num_erased = 1 + args.len(); - let erased_ret = eraser - .erase_transparent_types(library, ret, mappings) - .unwrap_or_else(|| { - num_erased -= 1; - ret.as_ref().clone() - }); - + // Attempt to erase ret and all args; if any of them were actually erased, then + // assemble and return the simplified function signature that results. + let mut erased_any = false; + let mut try_erase = |ty| { + if let Some(erased) = eraser.erase_transparent_types(library, ty, mappings) { + erased_any = true; + erased + } else { + ty.clone() + } + }; + let erased_ret = try_erase(ret); let erased_args = args .iter() - .map(|(name, ty)| { - let erased_ty = eraser - .erase_transparent_types(library, ty, mappings) - .unwrap_or_else(|| { - num_erased -= 1; - ty.clone() - }); - (name.clone(), erased_ty) - }) + .map(|(name, ty)| (name.clone(), try_erase(ty))) .collect(); - if num_erased > 0 { + if erased_any { return Some(Type::FuncPtr { ret: Box::new(erased_ret), args: erased_args, From afa9286da59cb8d1e0aa89a9b66daeb10061bcaf Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 22 May 2024 10:13:12 -0700 Subject: [PATCH 3/3] Add support for transparent enum --- docs.md | 16 +- src/bindgen/ir/enumeration.rs | 61 ++++- src/bindgen/ir/structure.rs | 12 +- src/bindgen/ir/ty.rs | 1 + src/bindgen/ir/typedef.rs | 8 +- src/bindgen/language_backend/mod.rs | 23 +- tests/expectations/const_transparent.compat.c | 12 + tests/expectations/const_transparent.cpp | 15 ++ tests/expectations/const_transparent.pyx | 12 + tests/expectations/transparent.c | 119 ++++++++-- tests/expectations/transparent.compat.c | 119 ++++++++-- tests/expectations/transparent.cpp | 125 ++++++++-- tests/expectations/transparent.pyx | 117 ++++++++-- tests/expectations/transparent_both.c | 121 ++++++++-- tests/expectations/transparent_both.compat.c | 121 ++++++++-- tests/expectations/transparent_tag.c | 119 ++++++++-- tests/expectations/transparent_tag.compat.c | 119 ++++++++-- tests/expectations/transparent_tag.pyx | 117 ++++++++-- tests/rust/const_transparent.rs | 32 +++ tests/rust/transparent.rs | 217 ++++++++++++++---- 20 files changed, 1223 insertions(+), 263 deletions(-) diff --git a/docs.md b/docs.md index ad5dcc188..bd66f5d1e 100644 --- a/docs.md +++ b/docs.md @@ -133,10 +133,12 @@ You can learn about all of the different repr attributes [by reading Rust's refe * `#[repr(C)]`: give this struct/union/enum the same layout and ABI C would * `#[repr(u8, u16, ... etc)]`: give this enum the same layout and ABI as the given integer type -* `#[repr(transparent)]`: give this single-field struct the same ABI as its field (useful for newtyping integers but keeping the integer ABI) +* `#[repr(transparent)]`: give this single-field struct or enum the same ABI as its field (useful for newtyping integers but keeping the integer ABI) cbindgen supports the `#[repr(align(N))]` and `#[repr(packed)]` attributes, but currently does not support `#[repr(packed(N))]`. +cbindgen supports using `repr(transparent)` on single-field structs and single-variant enums with fields. Transparent structs and enums are exported as typedefs that alias the underlying single field's type. + cbindgen also supports using `repr(C)`/`repr(u8)` on non-C-like enums (enums with fields). This gives a C-compatible tagged union layout, as [defined by this RFC 2195][really-tagged-unions]. `repr(C)` will give a simpler layout that is perhaps more intuitive, while `repr(u8)` will produce a more compact layout. If you ensure everything has a guaranteed repr, then cbindgen will generate definitions for: @@ -407,9 +409,17 @@ The rest are just local overrides for the same options found in the cbindgen.tom ### Enum Annotations -* enum-trailing-values=\[variant1, variant2, ...\] -- add the following fieldless enum variants to the end of the enum's definition. These variant names *will* have the enum's renaming rules applied. +* enum-trailing-values=\[variant1, variant2, ...\] -- add the following fieldless enum variants to + the end of the enum's definition. These variant names *will* have the enum's renaming rules + applied. + + WARNING: if any of these values are ever passed into Rust, behaviour will be Undefined. Rust does + not know about them, and will assume they cannot happen. -WARNING: if any of these values are ever passed into Rust, behaviour will be Undefined. Rust does not know about them, and will assume they cannot happen. +* transparent-typedef -- when emitting the typedef for a transparent enum, mark it as + transparent. All references to the enum will be replaced with the type of its underlying NZST + variant field, effectively making the enum invisible on the FFI side. For exmaples of how this + works, see [Struct Annotations](#struct-annotations). The rest are just local overrides for the same options found in the cbindgen.toml: diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index f5a0bbeed..c800c3d45 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -12,7 +12,7 @@ use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr, - ReprStyle, Struct, ToCondition, TransparentTypeEraser, Type, + ReprStyle, Struct, ToCondition, TransparentTypeEraser, Type, Typedef, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -308,7 +308,12 @@ impl Enum { /// Enum with data turns into a union of structs with each struct having its own tag field. pub(crate) fn inline_tag_field(repr: &Repr) -> bool { - repr.style != ReprStyle::C + // NOTE: repr(C) requires an out of line tag field, and repr(transparent) doesn't use tags. + repr.style == ReprStyle::Rust + } + + pub fn is_transparent(&self) -> bool { + self.repr.style == ReprStyle::Transparent } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { @@ -345,7 +350,7 @@ impl Enum { ) -> Result { let repr = Repr::load(&item.attrs)?; if repr.style == ReprStyle::Rust && repr.ty.is_none() { - return Err("Enum is not marked with a valid #[repr(prim)] or #[repr(C)].".to_owned()); + return Err("Enum is not marked with a valid #[repr(prim)] or #[repr(C)] or #[repr(transparent)].".to_owned()); } // TODO: Implement translation of aligned enums. if repr.align.is_some() { @@ -418,13 +423,35 @@ impl Enum { pub fn new( path: Path, generic_params: GenericParams, - repr: Repr, + mut repr: Repr, variants: Vec, tag: Option, cfg: Option, annotations: AnnotationSet, documentation: Documentation, ) -> Self { + // WARNING: A transparent enum with no fields (or whose fields are all 1-ZST) is legal rust + // [1], but it is a zero-sized type and as such is "best avoided entirely" [2] because it + // "will be nonsensical or problematic if passed through the FFI boundary" [1]. Further, + // because no well-defined underlying native type exists for a 1-ZST, we cannot emit a + // typedef and must fall back to repr(C) behavior that defines a tagged enum. + // + // [1] https://doc.rust-lang.org/nomicon/other-reprs.html + // [2] https://github.com/rust-lang/rust/issues/77841#issuecomment-716796313 + if repr.style == ReprStyle::Transparent { + let zero_sized = match variants.first() { + Some(EnumVariant { + body: VariantBody::Body { ref body, .. }, + .. + }) => body.fields.is_empty(), + _ => true, + }; + if zero_sized { + warn!("Passing zero-sized transparent enum {} across the FFI boundary is undefined behavior", &path); + repr.style = ReprStyle::C; + } + } + let export_name = path.name().to_owned(); Self { path, @@ -438,6 +465,28 @@ impl Enum { documentation, } } + + /// Attempts to convert this enum to a typedef (only works for transparent enums). + pub fn as_typedef(&self) -> Option { + if self.is_transparent() { + if let Some(EnumVariant { + body: VariantBody::Body { ref body, .. }, + .. + }) = self.variants.first() + { + if let Some(field) = body.fields.first() { + return Some(Typedef::new_from_item_field(self, field)); + } + } + } + None + } + + // Transparent enums become typedefs, so try converting to typedef and recurse on that. + pub fn as_transparent_alias(&self, generics: &[GenericArgument]) -> Option { + self.as_typedef() + .and_then(|t| t.as_transparent_alias(generics)) + } } impl Item for Enum { @@ -470,7 +519,9 @@ impl Item for Enum { } fn collect_declaration_types(&self, resolver: &mut DeclarationTypeResolver) { - if self.tag.is_some() { + if self.repr.style == ReprStyle::Transparent { + resolver.add_none(&self.path); + } else if self.tag.is_some() { if self.repr.style == ReprStyle::C { resolver.add_struct(&self.path); } else { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 602c8a934..a301cda05 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -136,10 +136,12 @@ impl Struct { // [2] https://github.com/rust-lang/rust/issues/77841#issuecomment-716796313 // [3] https://doc.rust-lang.org/nomicon/other-reprs.html if fields.is_empty() { - warn!( - "Passing zero-sized struct {} across the FFI boundary is undefined behavior", - &path - ); + if !is_enum_variant_body { + warn!( + "Passing zero-sized struct {} across the FFI boundary is undefined behavior", + &path + ); + } is_transparent = false; } @@ -163,7 +165,7 @@ impl Struct { /// Attempts to convert this struct to a typedef (only works for transparent structs). pub fn as_typedef(&self) -> Option { match self.fields.first() { - Some(field) if self.is_transparent => Some(Typedef::new_from_struct_field(self, field)), + Some(field) if self.is_transparent => Some(Typedef::new_from_item_field(self, field)), _ => None, } } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 78690ecaa..739db5eb1 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -569,6 +569,7 @@ impl Type { ItemContainer::OpaqueItem(o) => o.as_transparent_alias(&generics), ItemContainer::Typedef(t) => t.as_transparent_alias(&generics), ItemContainer::Struct(s) => s.as_transparent_alias(&generics), + ItemContainer::Enum(e) => e.as_transparent_alias(&generics), _ => None, }; if let Some(mut ty) = aliased_ty { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 580cea33f..becfefe6d 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, - Path, Struct, TransparentTypeEraser, Type, + Path, TransparentTypeEraser, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -69,12 +69,12 @@ impl Typedef { } } - // Used to convert a transparent Struct to a Typedef. - pub fn new_from_struct_field(item: &Struct, field: &Field) -> Self { + // Used to convert a transparent Struct or Enum to a Typedef. + pub fn new_from_item_field(item: &impl Item, field: &Field) -> Self { Self { path: item.path().clone(), export_name: item.export_name().to_string(), - generic_params: item.generic_params.clone(), + generic_params: item.generic_params().clone(), aliased: field.ty.clone(), cfg: item.cfg().cloned(), annotations: item.annotations().clone(), diff --git a/src/bindgen/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index 065bade20..6d9e5454f 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -157,6 +157,27 @@ pub trait LanguageBackend: Sized { } } + /// If the enum is transparent, emit a typedef of its NZST field type instead. + fn write_enum_or_typedef( + &mut self, + out: &mut SourceWriter, + e: &Enum, + _b: &Bindings, + ) { + if let Some(typedef) = e.as_typedef() { + self.write_type_def(out, &typedef); + // TODO: Associated constants are not supported for enums. Should they be? Rust + // enum exports as a union, and C/C++ at least supports static union members? + // + //for constant in &e.associated_constants { + // out.new_line(); + // constant.write(b.config, self, out, Some(e)); + //} + } else { + self.write_enum(out, e); + } + } + fn write_items(&mut self, out: &mut SourceWriter, b: &Bindings) { for item in &b.items { if item @@ -172,7 +193,7 @@ pub trait LanguageBackend: Sized { match *item { ItemContainer::Constant(..) => unreachable!(), ItemContainer::Static(..) => unreachable!(), - ItemContainer::Enum(ref x) => self.write_enum(out, x), + ItemContainer::Enum(ref x) => self.write_enum_or_typedef(out, x, b), ItemContainer::Struct(ref x) => self.write_struct_or_typedef(out, x, b), ItemContainer::Union(ref x) => self.write_union(out, x), ItemContainer::OpaqueItem(ref x) => self.write_opaque_item(out, x), diff --git a/tests/expectations/const_transparent.compat.c b/tests/expectations/const_transparent.compat.c index 62100f779..8d296ae85 100644 --- a/tests/expectations/const_transparent.compat.c +++ b/tests/expectations/const_transparent.compat.c @@ -3,6 +3,8 @@ #include #include +#define TransparentEnum_ASSOC_ENUM_FOO 8 + typedef uint8_t TransparentStruct; #define TransparentStruct_ASSOC_STRUCT_FOO 1 #define TransparentStruct_ASSOC_STRUCT_BAR 2 @@ -10,6 +12,8 @@ typedef uint8_t TransparentStruct; typedef uint8_t TransparentTupleStruct; +typedef uint8_t TransparentEnum; + #define STRUCT_FOO 4 #define STRUCT_BAR 5 @@ -17,3 +21,11 @@ typedef uint8_t TransparentTupleStruct; + + + + + + + + diff --git a/tests/expectations/const_transparent.cpp b/tests/expectations/const_transparent.cpp index 285fd8eaf..6a483045b 100644 --- a/tests/expectations/const_transparent.cpp +++ b/tests/expectations/const_transparent.cpp @@ -4,6 +4,8 @@ #include #include +constexpr static const int64_t TransparentEnum_ASSOC_ENUM_FOO = 8; + template using Wrapper = T; @@ -17,6 +19,11 @@ using TransparentTupleStruct = uint8_t; template using TransparentStructWithErasedField = T; +using TransparentEnum = uint8_t; + +template +using TransparentWrapperEnum = T; + constexpr static const TransparentStruct STRUCT_FOO = 4; constexpr static const TransparentTupleStruct STRUCT_BAR = 5; @@ -24,3 +31,11 @@ constexpr static const TransparentTupleStruct STRUCT_BAR = 5; constexpr static const TransparentStruct STRUCT_BAZ = 6; constexpr static const TransparentStructWithErasedField COMPLEX = 7; + + + + + + + + diff --git a/tests/expectations/const_transparent.pyx b/tests/expectations/const_transparent.pyx index c0993a3ae..c1b5c838e 100644 --- a/tests/expectations/const_transparent.pyx +++ b/tests/expectations/const_transparent.pyx @@ -6,6 +6,8 @@ cdef extern from *: cdef extern from *: + const int64_t TransparentEnum_ASSOC_ENUM_FOO # = 8 + ctypedef uint8_t TransparentStruct; const int64_t TransparentStruct_ASSOC_STRUCT_FOO # = 1 const TransparentStruct TransparentStruct_ASSOC_STRUCT_BAR # = 2 @@ -13,6 +15,8 @@ cdef extern from *: ctypedef uint8_t TransparentTupleStruct; + ctypedef uint8_t TransparentEnum; + const TransparentStruct STRUCT_FOO # = 4 const TransparentTupleStruct STRUCT_BAR # = 5 @@ -20,3 +24,11 @@ cdef extern from *: + + + + + + + + diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 80569f155..c31109f7f 100644 --- a/tests/expectations/transparent.c +++ b/tests/expectations/transparent.c @@ -3,6 +3,10 @@ #include #include +typedef enum { + NoData, +} TransparentEnumWithNoData; + typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; @@ -13,53 +17,97 @@ typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef DummyStruct TransparentComplexWrappingStructure; +typedef DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef DummyStruct TransparentComplexWrapper_i32; +typedef DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 typedef struct { -} TransparentEmptyStructure; +} TransparentEmptyStruct; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +typedef enum { + EmptyData, +} TransparentEnumWithEmptyData_Tag; + +typedef struct { + +} EmptyData_Body; + +typedef struct { + TransparentEnumWithEmptyData_Tag tag; + union { + EmptyData_Body empty_data; + }; +} TransparentEnumWithEmptyData; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - StructWithAssociatedConstantInImpl j, - EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -71,3 +119,30 @@ void erased_root(uint32_t *a, TransparentTransparentStruct l, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); + +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + TransparentEnumWithNoData g, + TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); diff --git a/tests/expectations/transparent.compat.c b/tests/expectations/transparent.compat.c index 2cf10ed9e..6bfcbe02d 100644 --- a/tests/expectations/transparent.compat.c +++ b/tests/expectations/transparent.compat.c @@ -3,6 +3,10 @@ #include #include +typedef enum { + NoData, +} TransparentEnumWithNoData; + typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; @@ -13,57 +17,101 @@ typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef DummyStruct TransparentComplexWrappingStructure; +typedef DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef DummyStruct TransparentComplexWrapper_i32; +typedef DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 typedef struct { -} TransparentEmptyStructure; +} TransparentEmptyStruct; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +typedef enum { + EmptyData, +} TransparentEnumWithEmptyData_Tag; + +typedef struct { + +} EmptyData_Body; + +typedef struct { + TransparentEnumWithEmptyData_Tag tag; + union { + EmptyData_Body empty_data; + }; +} TransparentEnumWithEmptyData; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { #endif // __cplusplus -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - StructWithAssociatedConstantInImpl j, - EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -76,6 +124,33 @@ void erased_root(uint32_t *a, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + TransparentEnumWithNoData g, + TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index 4459f2463..c4bf9ef05 100644 --- a/tests/expectations/transparent.cpp +++ b/tests/expectations/transparent.cpp @@ -4,6 +4,10 @@ #include #include +enum class TransparentEnumWithNoData { + NoData, +}; + struct DummyStruct; struct EnumWithAssociatedConstantInImpl; @@ -14,57 +18,103 @@ using TransparentComplexWrappingStructTuple = DummyStruct; using TransparentPrimitiveWrappingStructTuple = uint32_t; -using TransparentComplexWrappingStructure = DummyStruct; +using TransparentComplexWrappingStruct = DummyStruct; -using TransparentPrimitiveWrappingStructure = uint32_t; +using TransparentPrimitiveWrappingStruct = uint32_t; template -using TransparentComplexWrapper = DummyStruct; +using TransparentComplexWrapperStruct = DummyStruct; template -using TransparentPrimitiveWrapper = uint32_t; +using TransparentPrimitiveWrapperStruct = uint32_t; -using TransparentPrimitiveWithAssociatedConstants = uint32_t; -constexpr static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ZERO = 0; -constexpr static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ONE = 1; +using TransparentPrimitiveStructWithAssociatedConstants = uint32_t; +constexpr static const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO = 0; +constexpr static const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE = 1; -struct TransparentEmptyStructure { +struct TransparentEmptyStruct { }; -using TransparentPointerWrappingStructure = const uint32_t*; +using TransparentPointerWrappingStruct = const uint32_t*; using TransparentIntStruct = int32_t; using TransparentComplexStruct = DummyStruct; -using TransparentTransparentStruct = TransparentPrimitiveWrappingStructure; +using TransparentTransparentStruct = TransparentPrimitiveWrappingStruct; using TransparentNonNullStruct = uint32_t*; using TransparentOptionNonNullStruct = uint32_t*; -constexpr static const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN = 10; +using TransparentComplexWrappingEnumTuple = DummyStruct; + +using TransparentPrimitiveWrappingEnumTuple = uint32_t; + +using TransparentComplexWrappingEnum = DummyStruct; + +using TransparentPrimitiveWrappingEnum = uint32_t; + +template +using TransparentComplexWrapperEnum = DummyStruct; + +template +using TransparentPrimitiveWrapperEnum = uint32_t; + +struct TransparentEnumWithEmptyData { + enum class Tag { + EmptyData, + }; + + struct EmptyData_Body { + + }; + + Tag tag; + union { + EmptyData_Body empty_data; + }; +}; -constexpr static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN = 10; +using TransparentPrimitiveEnumWithAssociatedConstants = uint32_t; + +using TransparentPointerWrappingEnum = const uint32_t*; + +using TransparentIntEnum = int32_t; + +using TransparentComplexEnum = DummyStruct; + +using TransparentTransparentEnum = TransparentPrimitiveWrappingEnum; + +using TransparentNonNullEnum = uint32_t*; + +using TransparentOptionNonNullEnum = uint32_t*; + +constexpr static const TransparentPrimitiveWrappingStruct StructWithAssociatedConstantInImpl_STRUCT_TEN = 10; + + + + + +constexpr static const TransparentPrimitiveWrappingStruct EnumWithAssociatedConstantInImpl_ENUM_TEN = 10; extern "C" { -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper e, - TransparentPrimitiveWrapper f, - TransparentPrimitiveWithAssociatedConstants g, - TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - StructWithAssociatedConstantInImpl j, - EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct e, + TransparentPrimitiveWrapperStruct f, + TransparentPrimitiveStructWithAssociatedConstants g, + TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -77,4 +127,31 @@ void erased_root(uint32_t *a, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum e, + TransparentPrimitiveWrapperEnum f, + TransparentEnumWithNoData g, + TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); + } // extern "C" diff --git a/tests/expectations/transparent.pyx b/tests/expectations/transparent.pyx index e300f99ae..894e92ec2 100644 --- a/tests/expectations/transparent.pyx +++ b/tests/expectations/transparent.pyx @@ -6,6 +6,9 @@ cdef extern from *: cdef extern from *: + ctypedef enum TransparentEnumWithNoData: + NoData, + ctypedef struct DummyStruct: pass @@ -19,52 +22,91 @@ cdef extern from *: ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; - ctypedef DummyStruct TransparentComplexWrappingStructure; + ctypedef DummyStruct TransparentComplexWrappingStruct; - ctypedef uint32_t TransparentPrimitiveWrappingStructure; + ctypedef uint32_t TransparentPrimitiveWrappingStruct; - ctypedef DummyStruct TransparentComplexWrapper_i32; + ctypedef DummyStruct TransparentComplexWrapperStruct_i32; - ctypedef uint32_t TransparentPrimitiveWrapper_i32; + ctypedef uint32_t TransparentPrimitiveWrapperStruct_i32; - ctypedef uint32_t TransparentPrimitiveWithAssociatedConstants; - const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ZERO # = 0 - const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ONE # = 1 + ctypedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; + const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO # = 0 + const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE # = 1 - ctypedef struct TransparentEmptyStructure: + ctypedef struct TransparentEmptyStruct: pass - ctypedef const uint32_t *TransparentPointerWrappingStructure; + ctypedef const uint32_t *TransparentPointerWrappingStruct; ctypedef int32_t TransparentIntStruct; ctypedef DummyStruct TransparentComplexStruct; - ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + ctypedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; ctypedef uint32_t *TransparentNonNullStruct; ctypedef uint32_t *TransparentOptionNonNullStruct; - const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + ctypedef DummyStruct TransparentComplexWrappingEnumTuple; + + ctypedef uint32_t TransparentPrimitiveWrappingEnumTuple; + + ctypedef DummyStruct TransparentComplexWrappingEnum; + + ctypedef uint32_t TransparentPrimitiveWrappingEnum; + + ctypedef DummyStruct TransparentComplexWrapperEnum_i32; + + ctypedef uint32_t TransparentPrimitiveWrapperEnum_i32; + + ctypedef enum TransparentEnumWithEmptyData_Tag: + EmptyData, + + ctypedef struct EmptyData_Body: + pass + + ctypedef struct TransparentEnumWithEmptyData: + TransparentEnumWithEmptyData_Tag tag; + EmptyData_Body empty_data; + + ctypedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + + ctypedef const uint32_t *TransparentPointerWrappingEnum; - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 + ctypedef int32_t TransparentIntEnum; - void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - StructWithAssociatedConstantInImpl j, - EnumWithAssociatedConstantInImpl k); + ctypedef DummyStruct TransparentComplexEnum; + + ctypedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + + ctypedef uint32_t *TransparentNonNullEnum; + + ctypedef uint32_t *TransparentOptionNonNullEnum; + + const TransparentPrimitiveWrappingStruct StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + + + + + const TransparentPrimitiveWrappingStruct EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 + + void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -76,3 +118,30 @@ cdef extern from *: TransparentTransparentStruct l, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); + + void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + TransparentEnumWithNoData g, + TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + EnumWithAssociatedConstantInImpl k); + + void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); diff --git a/tests/expectations/transparent_both.c b/tests/expectations/transparent_both.c index 042009d51..b7ea5d0d7 100644 --- a/tests/expectations/transparent_both.c +++ b/tests/expectations/transparent_both.c @@ -3,6 +3,10 @@ #include #include +typedef enum TransparentEnumWithNoData { + NoData, +} TransparentEnumWithNoData; + typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; @@ -13,53 +17,97 @@ typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef struct DummyStruct TransparentComplexWrappingStructure; +typedef struct DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef struct DummyStruct TransparentComplexWrapper_i32; +typedef struct DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 -typedef struct TransparentEmptyStructure { +typedef struct TransparentEmptyStruct { -} TransparentEmptyStructure; +} TransparentEmptyStruct; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef struct DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef struct DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef struct DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef struct DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +typedef enum TransparentEnumWithEmptyData_Tag { + EmptyData, +} TransparentEnumWithEmptyData_Tag; + +typedef struct EmptyData_Body { + +} EmptyData_Body; + +typedef struct TransparentEnumWithEmptyData { + TransparentEnumWithEmptyData_Tag tag; + union { + EmptyData_Body empty_data; + }; +} TransparentEnumWithEmptyData; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef struct DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - struct TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - struct StructWithAssociatedConstantInImpl j, - struct EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + struct TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + struct StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -71,3 +119,30 @@ void erased_root(uint32_t *a, TransparentTransparentStruct l, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); + +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + enum TransparentEnumWithNoData g, + struct TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); diff --git a/tests/expectations/transparent_both.compat.c b/tests/expectations/transparent_both.compat.c index 21872104d..c087ed725 100644 --- a/tests/expectations/transparent_both.compat.c +++ b/tests/expectations/transparent_both.compat.c @@ -3,6 +3,10 @@ #include #include +typedef enum TransparentEnumWithNoData { + NoData, +} TransparentEnumWithNoData; + typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; @@ -13,57 +17,101 @@ typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef struct DummyStruct TransparentComplexWrappingStructure; +typedef struct DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef struct DummyStruct TransparentComplexWrapper_i32; +typedef struct DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 -typedef struct TransparentEmptyStructure { +typedef struct TransparentEmptyStruct { -} TransparentEmptyStructure; +} TransparentEmptyStruct; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef struct DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef struct DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef struct DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef struct DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +typedef enum TransparentEnumWithEmptyData_Tag { + EmptyData, +} TransparentEnumWithEmptyData_Tag; + +typedef struct EmptyData_Body { + +} EmptyData_Body; + +typedef struct TransparentEnumWithEmptyData { + TransparentEnumWithEmptyData_Tag tag; + union { + EmptyData_Body empty_data; + }; +} TransparentEnumWithEmptyData; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef struct DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { #endif // __cplusplus -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - struct TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - struct StructWithAssociatedConstantInImpl j, - struct EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + struct TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + struct StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -76,6 +124,33 @@ void erased_root(uint32_t *a, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + enum TransparentEnumWithNoData g, + struct TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/transparent_tag.c b/tests/expectations/transparent_tag.c index 6589eb6bc..0eeec963f 100644 --- a/tests/expectations/transparent_tag.c +++ b/tests/expectations/transparent_tag.c @@ -3,6 +3,10 @@ #include #include +enum TransparentEnumWithNoData { + NoData, +}; + struct DummyStruct; struct EnumWithAssociatedConstantInImpl; @@ -13,53 +17,97 @@ typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef struct DummyStruct TransparentComplexWrappingStructure; +typedef struct DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef struct DummyStruct TransparentComplexWrapper_i32; +typedef struct DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 -struct TransparentEmptyStructure { +struct TransparentEmptyStruct { }; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef struct DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef struct DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef struct DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef struct DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +enum TransparentEnumWithEmptyData_Tag { + EmptyData, +}; + +struct EmptyData_Body { + +}; + +struct TransparentEnumWithEmptyData { + enum TransparentEnumWithEmptyData_Tag tag; + union { + struct EmptyData_Body empty_data; + }; +}; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef struct DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - struct TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - struct StructWithAssociatedConstantInImpl j, - struct EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + struct TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + struct StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -71,3 +119,30 @@ void erased_root(uint32_t *a, TransparentTransparentStruct l, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); + +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + enum TransparentEnumWithNoData g, + struct TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); diff --git a/tests/expectations/transparent_tag.compat.c b/tests/expectations/transparent_tag.compat.c index 2eff06ef0..6c9d1a084 100644 --- a/tests/expectations/transparent_tag.compat.c +++ b/tests/expectations/transparent_tag.compat.c @@ -3,6 +3,10 @@ #include #include +enum TransparentEnumWithNoData { + NoData, +}; + struct DummyStruct; struct EnumWithAssociatedConstantInImpl; @@ -13,57 +17,101 @@ typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; -typedef struct DummyStruct TransparentComplexWrappingStructure; +typedef struct DummyStruct TransparentComplexWrappingStruct; -typedef uint32_t TransparentPrimitiveWrappingStructure; +typedef uint32_t TransparentPrimitiveWrappingStruct; -typedef struct DummyStruct TransparentComplexWrapper_i32; +typedef struct DummyStruct TransparentComplexWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWrapperStruct_i32; -typedef uint32_t TransparentPrimitiveWithAssociatedConstants; -#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 -#define TransparentPrimitiveWithAssociatedConstants_ONE 1 +typedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO 0 +#define TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE 1 -struct TransparentEmptyStructure { +struct TransparentEmptyStruct { }; -typedef const uint32_t *TransparentPointerWrappingStructure; +typedef const uint32_t *TransparentPointerWrappingStruct; typedef int32_t TransparentIntStruct; typedef struct DummyStruct TransparentComplexStruct; -typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; +typedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; typedef uint32_t *TransparentNonNullStruct; typedef uint32_t *TransparentOptionNonNullStruct; +typedef struct DummyStruct TransparentComplexWrappingEnumTuple; + +typedef uint32_t TransparentPrimitiveWrappingEnumTuple; + +typedef struct DummyStruct TransparentComplexWrappingEnum; + +typedef uint32_t TransparentPrimitiveWrappingEnum; + +typedef struct DummyStruct TransparentComplexWrapperEnum_i32; + +typedef uint32_t TransparentPrimitiveWrapperEnum_i32; + +enum TransparentEnumWithEmptyData_Tag { + EmptyData, +}; + +struct EmptyData_Body { + +}; + +struct TransparentEnumWithEmptyData { + enum TransparentEnumWithEmptyData_Tag tag; + union { + struct EmptyData_Body empty_data; + }; +}; + +typedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + +typedef const uint32_t *TransparentPointerWrappingEnum; + +typedef int32_t TransparentIntEnum; + +typedef struct DummyStruct TransparentComplexEnum; + +typedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + +typedef uint32_t *TransparentNonNullEnum; + +typedef uint32_t *TransparentOptionNonNullEnum; + #define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + + + + #define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { #endif // __cplusplus -void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - struct TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - struct StructWithAssociatedConstantInImpl j, - struct EnumWithAssociatedConstantInImpl k); +void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + struct TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + struct StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -76,6 +124,33 @@ void erased_root(uint32_t *a, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); +void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + enum TransparentEnumWithNoData g, + struct TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/transparent_tag.pyx b/tests/expectations/transparent_tag.pyx index 204452d64..bbc3b3ddc 100644 --- a/tests/expectations/transparent_tag.pyx +++ b/tests/expectations/transparent_tag.pyx @@ -6,6 +6,9 @@ cdef extern from *: cdef extern from *: + cdef enum TransparentEnumWithNoData: + NoData, + cdef struct DummyStruct: pass @@ -19,52 +22,91 @@ cdef extern from *: ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; - ctypedef DummyStruct TransparentComplexWrappingStructure; + ctypedef DummyStruct TransparentComplexWrappingStruct; - ctypedef uint32_t TransparentPrimitiveWrappingStructure; + ctypedef uint32_t TransparentPrimitiveWrappingStruct; - ctypedef DummyStruct TransparentComplexWrapper_i32; + ctypedef DummyStruct TransparentComplexWrapperStruct_i32; - ctypedef uint32_t TransparentPrimitiveWrapper_i32; + ctypedef uint32_t TransparentPrimitiveWrapperStruct_i32; - ctypedef uint32_t TransparentPrimitiveWithAssociatedConstants; - const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ZERO # = 0 - const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ONE # = 1 + ctypedef uint32_t TransparentPrimitiveStructWithAssociatedConstants; + const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ZERO # = 0 + const TransparentPrimitiveStructWithAssociatedConstants TransparentPrimitiveStructWithAssociatedConstants_STRUCT_ONE # = 1 - cdef struct TransparentEmptyStructure: + cdef struct TransparentEmptyStruct: pass - ctypedef const uint32_t *TransparentPointerWrappingStructure; + ctypedef const uint32_t *TransparentPointerWrappingStruct; ctypedef int32_t TransparentIntStruct; ctypedef DummyStruct TransparentComplexStruct; - ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + ctypedef TransparentPrimitiveWrappingStruct TransparentTransparentStruct; ctypedef uint32_t *TransparentNonNullStruct; ctypedef uint32_t *TransparentOptionNonNullStruct; - const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + ctypedef DummyStruct TransparentComplexWrappingEnumTuple; + + ctypedef uint32_t TransparentPrimitiveWrappingEnumTuple; + + ctypedef DummyStruct TransparentComplexWrappingEnum; + + ctypedef uint32_t TransparentPrimitiveWrappingEnum; + + ctypedef DummyStruct TransparentComplexWrapperEnum_i32; + + ctypedef uint32_t TransparentPrimitiveWrapperEnum_i32; + + cdef enum TransparentEnumWithEmptyData_Tag: + EmptyData, + + cdef struct EmptyData_Body: + pass + + cdef struct TransparentEnumWithEmptyData: + TransparentEnumWithEmptyData_Tag tag; + EmptyData_Body empty_data; + + ctypedef uint32_t TransparentPrimitiveEnumWithAssociatedConstants; + + ctypedef const uint32_t *TransparentPointerWrappingEnum; - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 + ctypedef int32_t TransparentIntEnum; - void root(TransparentComplexWrappingStructTuple a, - TransparentPrimitiveWrappingStructTuple b, - TransparentComplexWrappingStructure c, - TransparentPrimitiveWrappingStructure d, - TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g, - TransparentEmptyStructure h, - TransparentPointerWrappingStructure i, - StructWithAssociatedConstantInImpl j, - EnumWithAssociatedConstantInImpl k); + ctypedef DummyStruct TransparentComplexEnum; + + ctypedef TransparentPrimitiveWrappingEnum TransparentTransparentEnum; + + ctypedef uint32_t *TransparentNonNullEnum; + + ctypedef uint32_t *TransparentOptionNonNullEnum; + + const TransparentPrimitiveWrappingStruct StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + + + + + const TransparentPrimitiveWrappingStruct EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 + + void struct_root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStruct c, + TransparentPrimitiveWrappingStruct d, + TransparentComplexWrapperStruct_i32 e, + TransparentPrimitiveWrapperStruct_i32 f, + TransparentPrimitiveStructWithAssociatedConstants g, + TransparentEmptyStruct h, + TransparentPointerWrappingStruct i, + StructWithAssociatedConstantInImpl j); void erased_root(uint32_t *a, uint32_t *b, - TransparentPrimitiveWrappingStructure c, + TransparentPrimitiveWrappingStruct c, uint32_t *d, TransparentIntStruct e, int32_t f, @@ -76,3 +118,30 @@ cdef extern from *: TransparentTransparentStruct l, TransparentNonNullStruct m, TransparentOptionNonNullStruct n); + + void enum_root(TransparentComplexWrappingEnumTuple a, + TransparentPrimitiveWrappingEnumTuple b, + TransparentComplexWrappingEnum c, + TransparentPrimitiveWrappingEnum d, + TransparentComplexWrapperEnum_i32 e, + TransparentPrimitiveWrapperEnum_i32 f, + TransparentEnumWithNoData g, + TransparentEnumWithEmptyData h, + TransparentPrimitiveEnumWithAssociatedConstants i, + TransparentPointerWrappingEnum j, + EnumWithAssociatedConstantInImpl k); + + void erased_enum_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingEnum c, + uint32_t *d, + TransparentIntEnum e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntEnum j, + TransparentComplexEnum k, + TransparentTransparentEnum l, + TransparentNonNullEnum m, + TransparentOptionNonNullEnum n); diff --git a/tests/rust/const_transparent.rs b/tests/rust/const_transparent.rs index 1e2e81c9b..c6c50d67c 100644 --- a/tests/rust/const_transparent.rs +++ b/tests/rust/const_transparent.rs @@ -31,3 +31,35 @@ struct TransparentStructWithErasedField { pub const COMPLEX: TransparentStructWithErasedField = TransparentStructWithErasedField { field: Wrapper { field: TransparentStruct { field: 7 } } }; + +#[repr(transparent)] +enum TransparentEnum { + A { field: u8 }, +} + +impl TransparentEnum { + pub const ASSOC_ENUM_FOO: i64 = 8; + + // TODO: Transparent enum constants are not supported yet. + pub const ASSOC_ENUM_BAR: TransparentEnum = TransparentEnum::A { field: 9 }; + pub const ASSOC_ENUM_BAZ: TransparentWrapperEnum = TransparentWrapperEnum::A { + field: TransparentEnum::A { field: 10 } + }; +} + +#[repr(transparent)] +enum TransparentTupleEnum { + A(u8), +} + +#[repr(transparent)] +enum TransparentWrapperEnum { + A { field: T }, +} + +// TODO: Transparent enum constants are not supported yet. +pub const ENUM_FOO: TransparentEnum = TransparentEnum::A { field: 11 }; +pub const ENUM_BAR: TransparentTupleEnum = TransparentTupleEnum::A(12); +pub const ENUM_BAZ: TransparentWrapperEnum = TransparentWrapperEnum::A { + field: TransparentEnum::A { field: 13 } +}; diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index fb812e334..abdc0dfe0 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -8,82 +8,72 @@ struct TransparentComplexWrappingStructTuple(DummyStruct); #[repr(transparent)] struct TransparentPrimitiveWrappingStructTuple(u32); -// Transparent structure wrapping a struct. +// Transparent struct wrapping a struct. #[repr(transparent)] -struct TransparentComplexWrappingStructure { only_field: DummyStruct } +struct TransparentComplexWrappingStruct { only_field: DummyStruct } -// Transparent structure wrapping a primitive. +// Transparent struct wrapping a primitive. #[repr(transparent)] -struct TransparentPrimitiveWrappingStructure { only_field: u32 } +struct TransparentPrimitiveWrappingStruct { only_field: u32 } // Transparent struct wrapping a pointer #[repr(transparent)] -struct TransparentPointerWrappingStructure { only_field: *const u32 } +struct TransparentPointerWrappingStruct { only_field: *const u32 } // Transparent struct wrapper with a marker wrapping a struct. #[repr(transparent)] -struct TransparentComplexWrapper { +struct TransparentComplexWrapperStruct { only_non_zero_sized_field: DummyStruct, marker: PhantomData, } // Transparent struct wrapper with a marker wrapping a primitive. #[repr(transparent)] -struct TransparentPrimitiveWrapper { +struct TransparentPrimitiveWrapperStruct { only_non_zero_sized_field: u32, marker: PhantomData, } // Associated constant declared before struct declaration. -impl TransparentPrimitiveWithAssociatedConstants { - pub const ZERO: TransparentPrimitiveWithAssociatedConstants = TransparentPrimitiveWithAssociatedConstants { - bits: 0 - }; +impl TransparentPrimitiveStructWithAssociatedConstants { + pub const STRUCT_ZERO: TransparentPrimitiveStructWithAssociatedConstants = + TransparentPrimitiveStructWithAssociatedConstants { bits: 0 }; } -// Transparent structure wrapping a primitive with associated constants. +// Transparent struct wrapping a primitive with associated constants. #[repr(transparent)] -struct TransparentPrimitiveWithAssociatedConstants { bits: u32 } +struct TransparentPrimitiveStructWithAssociatedConstants { bits: u32 } // Transparent zero-sized structs are legal rust, but there's no way to emit a typedef for one, so // cbindgen should treat it as repr(C) instead and emit an empty struct definition. #[repr(transparent)] -struct TransparentEmptyStructure; +struct TransparentEmptyStruct; // Associated constant declared after struct declaration. -impl TransparentPrimitiveWithAssociatedConstants { - pub const ONE: TransparentPrimitiveWithAssociatedConstants = TransparentPrimitiveWithAssociatedConstants { - bits: 1 - }; +impl TransparentPrimitiveStructWithAssociatedConstants { + pub const STRUCT_ONE: TransparentPrimitiveStructWithAssociatedConstants = + TransparentPrimitiveStructWithAssociatedConstants { bits: 1 }; } struct StructWithAssociatedConstantInImpl { } impl StructWithAssociatedConstantInImpl { - pub const STRUCT_TEN: TransparentPrimitiveWrappingStructure = - TransparentPrimitiveWrappingStructure { only_field: 10 }; -} - -enum EnumWithAssociatedConstantInImpl { A } - -impl EnumWithAssociatedConstantInImpl { - pub const ENUM_TEN: TransparentPrimitiveWrappingStructure = - TransparentPrimitiveWrappingStructure { only_field: 10 }; + pub const STRUCT_TEN: TransparentPrimitiveWrappingStruct = + TransparentPrimitiveWrappingStruct { only_field: 10 }; } #[no_mangle] -pub extern "C" fn root( +pub extern "C" fn struct_root( a: TransparentComplexWrappingStructTuple, b: TransparentPrimitiveWrappingStructTuple, - c: TransparentComplexWrappingStructure, - d: TransparentPrimitiveWrappingStructure, - e: TransparentComplexWrapper, - f: TransparentPrimitiveWrapper, - g: TransparentPrimitiveWithAssociatedConstants, - h: TransparentEmptyStructure, - i: TransparentPointerWrappingStructure, + c: TransparentComplexWrappingStruct, + d: TransparentPrimitiveWrappingStruct, + e: TransparentComplexWrapperStruct, + f: TransparentPrimitiveWrapperStruct, + g: TransparentPrimitiveStructWithAssociatedConstants, + h: TransparentEmptyStruct, + i: TransparentPointerWrappingStruct, j: StructWithAssociatedConstantInImpl, - k: EnumWithAssociatedConstantInImpl, ) { } #[repr(transparent)] @@ -96,20 +86,20 @@ struct ErasedTransparentOptionalNonNullPointerWrappingStruct { only_field: Optio #[repr(transparent)] /// cbindgen:transparent-typedef -struct ErasedTransparentWrappingAnotherTransparentStruct { only_field: TransparentPrimitiveWrappingStructure } +struct ErasedTransparentWrappingAnotherTransparentStruct { only_field: TransparentPrimitiveWrappingStruct } /// cbindgen:transparent-typedef #[repr(transparent)] struct ErasedTransparentWrappingTransparentNonNullPointerStruct { only_field: ErasedTransparentNonNullPointerWrappingStruct } -// Transparent structure wrapping another type +// Transparent struct wrapping another type #[repr(transparent)] /// cbindgen:transparent-typedef struct ErasedTransparentStructWrappingAnotherType { only_field: T } type TransparentIntStruct = ErasedTransparentStructWrappingAnotherType; type TransparentComplexStruct = ErasedTransparentStructWrappingAnotherType; -type TransparentTransparentStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentTransparentStruct = ErasedTransparentStructWrappingAnotherType; type TransparentNonNullStruct = ErasedTransparentStructWrappingAnotherType>; type TransparentOptionNonNullStruct = ErasedTransparentStructWrappingAnotherType>>; @@ -137,3 +127,152 @@ pub extern "C" fn erased_root( m: TransparentNonNullStruct, n: TransparentOptionNonNullStruct, ) { } + +// Transparent enum tuple wrapping a struct. +#[repr(transparent)] +enum TransparentComplexWrappingEnumTuple { + A(DummyStruct), +} + +// Transparent enum tuple wrapping a primitive. +#[repr(transparent)] +enum TransparentPrimitiveWrappingEnumTuple { + A(u32), +} + +// Transparent enum wrapping a struct. +#[repr(transparent)] +enum TransparentComplexWrappingEnum { + A { only_field: DummyStruct }, +} + +// Transparent enum wrapping a primitive. +#[repr(transparent)] +enum TransparentPrimitiveWrappingEnum { + A { only_field: u32 }, +} + +// Transparent enum wrapping a pointer +#[repr(transparent)] +enum TransparentPointerWrappingEnum { + A { only_field: *const u32 }, +} + +// Transparent enum wrapper with a marker wrapping a struct. +#[repr(transparent)] +enum TransparentComplexWrapperEnum { + A { only_non_zero_sized_field: DummyStruct }, + B { marker: PhantomData }, +} + +// Transparent enum wrapper with a marker wrapping a primitive. +#[repr(transparent)] +enum TransparentPrimitiveWrapperEnum { + C { only_non_zero_sized_field: u32 }, + D { marker: PhantomData }, +} + +// Transparent enums with missing or zero-sized data are legal rust, but there's no way to emit a +// transparent typedef for them, so cbindgen should treat them as repr(C) instead. +#[repr(transparent)] +enum TransparentEnumWithNoData { + NoData, +} +#[repr(transparent)] +enum TransparentEnumWithEmptyData { + EmptyData(), +} + +// Associated constant declared before enum declaration. +impl TransparentPrimitiveEnumWithAssociatedConstants { + // TODO: Transparent enum constants are not supported yet. + pub const ENUM_ZERO: TransparentPrimitiveEnumWithAssociatedConstants = + TransparentPrimitiveEnumWithAssociatedConstants::A { bits: 0 }; +} + +// Transparent enum wrapping a primitive with associated constants. +#[repr(transparent)] +enum TransparentPrimitiveEnumWithAssociatedConstants { + A { bits: u32 }, +} + +// Associated constant declared after enum declaration. +impl TransparentPrimitiveEnumWithAssociatedConstants { + // TODO: Transparent enum constants are not supported yet. + pub const ENUM_ONE: TransparentPrimitiveEnumWithAssociatedConstants = + TransparentPrimitiveEnumWithAssociatedConstants::A { bits: 1 }; +} + +enum EnumWithAssociatedConstantInImpl { A } + +impl EnumWithAssociatedConstantInImpl { + pub const ENUM_TEN: TransparentPrimitiveWrappingStruct = + TransparentPrimitiveWrappingStruct { only_field: 10 }; +} + +#[no_mangle] +pub extern "C" fn enum_root( + a: TransparentComplexWrappingEnumTuple, + b: TransparentPrimitiveWrappingEnumTuple, + c: TransparentComplexWrappingEnum, + d: TransparentPrimitiveWrappingEnum, + e: TransparentComplexWrapperEnum, + f: TransparentPrimitiveWrapperEnum, + g: TransparentEnumWithNoData, + h: TransparentEnumWithEmptyData, + i: TransparentPrimitiveEnumWithAssociatedConstants, + j: TransparentPointerWrappingEnum, + k: EnumWithAssociatedConstantInImpl, +) { } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +enum ErasedTransparentNonNullPointerWrappingEnum { A(NonNull) } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +enum ErasedTransparentOptionalNonNullPointerWrappingEnum { A(Option>) } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +enum ErasedTransparentWrappingAnotherTransparentEnum { A(TransparentPrimitiveWrappingEnum) } + +/// cbindgen:transparent-typedef +#[repr(transparent)] +enum ErasedTransparentWrappingTransparentNonNullPointerEnum { A(ErasedTransparentNonNullPointerWrappingEnum) } + +// Transparent enumure wrapping another type +#[repr(transparent)] +/// cbindgen:transparent-typedef +enum ErasedTransparentEnumWrappingAnotherType { A(T) } + +type TransparentIntEnum = ErasedTransparentEnumWrappingAnotherType; +type TransparentComplexEnum = ErasedTransparentEnumWrappingAnotherType; +type TransparentTransparentEnum = ErasedTransparentEnumWrappingAnotherType; +type TransparentNonNullEnum = ErasedTransparentEnumWrappingAnotherType>; +type TransparentOptionNonNullEnum = ErasedTransparentEnumWrappingAnotherType>>; + +/// cbindgen:transparent-typedef +type ErasedTransparentIntEnum = ErasedTransparentEnumWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentComplexEnum = ErasedTransparentEnumWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentOptionNonNullEnum = ErasedTransparentEnumWrappingAnotherType>>; + +#[no_mangle] +pub extern "C" fn erased_enum_root( + a: ErasedTransparentNonNullPointerWrappingEnum, + b: ErasedTransparentOptionalNonNullPointerWrappingEnum, + c: ErasedTransparentWrappingAnotherTransparentEnum, + d: ErasedTransparentWrappingTransparentNonNullPointerEnum, + e: ErasedTransparentEnumWrappingAnotherType, + f: ErasedTransparentEnumWrappingAnotherType, + g: ErasedTransparentEnumWrappingAnotherType, + h: ErasedTransparentEnumWrappingAnotherType, + i: ErasedTransparentIntEnum, + j: TransparentIntEnum, + k: TransparentComplexEnum, + l: TransparentTransparentEnum, + m: TransparentNonNullEnum, + n: TransparentOptionNonNullEnum, +) { }