From e5656ad6bb9005f0ebbe2c07c35053e6aae9b220 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Sat, 2 Nov 2024 13:02:44 -0700 Subject: [PATCH 01/13] wip transparent typedef take 2 --- src/bindgen/ir/constant.rs | 7 ++- src/bindgen/ir/enumeration.rs | 4 ++ src/bindgen/ir/global.rs | 7 ++- src/bindgen/ir/item.rs | 9 ++-- src/bindgen/ir/opaque.rs | 5 +++ src/bindgen/ir/structure.rs | 21 +++++++++ src/bindgen/ir/ty.rs | 67 +++++++++++++++++++++++++++-- src/bindgen/ir/typedef.rs | 17 ++++++++ src/bindgen/ir/union.rs | 6 ++- src/bindgen/language_backend/mod.rs | 7 +-- src/bindgen/library.rs | 19 +++++++- tests/tests.rs | 23 +++++----- 12 files changed, 164 insertions(+), 28 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index ca6499d8..477f2d9c 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, Type, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; @@ -603,6 +603,9 @@ impl Item for Constant { fn generic_params(&self) -> &GenericParams { GenericParams::empty() } + fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + None + } } impl Constant { diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 8927b8be..84acb084 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -501,6 +501,10 @@ impl Item for Enum { &self.generic_params } + fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + None + } + fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 7816a294..45d9cd87 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, + Type, }; use crate::bindgen::library::Library; @@ -109,6 +110,10 @@ impl Item for Static { GenericParams::empty() } + fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + None + } + 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 03e1c153..68a44b44 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, Type, Typedef, Union, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -43,6 +43,7 @@ pub trait Item { !self.generic_params().is_empty() } + fn transparent_alias(&self, generics: &[GenericArgument], _library: &Library) -> Option; fn rename_for_config(&mut self, _config: &Config) {} fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) {} fn instantiate_monomorph( @@ -66,8 +67,10 @@ pub enum ItemContainer { Typedef(Typedef), } -impl ItemContainer { - pub fn deref(&self) -> &dyn Item { +impl std::ops::Deref for ItemContainer { + type Target = dyn Item + 'static; + + fn deref(&self) -> &Self::Target { match *self { ItemContainer::Constant(ref x) => x, ItemContainer::Static(ref x) => x, diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4527e3ca..4d90ea44 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, + Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -94,6 +95,10 @@ impl Item for OpaqueItem { &self.generic_params } + fn transparent_alias(&self, generics: &[GenericArgument], _library: &Library) -> Option { + None // TODO! + } + 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 d805d69c..9be6f8ce 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -192,6 +192,23 @@ impl Struct { } } + pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { + let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library)).collect(); + if types.iter().all(Option::is_none) { + return None; + } + let fields = types.into_iter().zip(&self.fields).map(|(ty, field)| { + Field { + ty: ty.unwrap_or_else(|| field.ty.clone()), + ..field.clone() + } + }).collect(); + Some(Struct { + fields, + ..self.clone() + }) + } + pub fn specialize( &self, generic_values: &[GenericArgument], @@ -312,6 +329,10 @@ impl Item for Struct { &self.generic_params } + fn transparent_alias(&self, generics: &[GenericArgument], library: &Library) -> Option { + self.as_typedef().and_then(|t| t.transparent_alias(generics, library)) + } + 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 2d0d692a..7949eac9 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -627,6 +627,68 @@ impl Type { } } + /// If this type is transparent, recursively replace it with whatever type it aliases. + pub fn transparent_alias(&self, library: &Library) -> Option { + match self { + Type::Ptr { + ty, + is_const, + is_nullable, + is_ref, + } => Some(Type::Ptr { + ty: Box::new(ty.transparent_alias(library)?), + is_const: *is_const, + is_nullable: *is_nullable, + is_ref: *is_ref, + }), + Type::Path(generic_path) => { + let mut erased_types = library + .get_items(generic_path.path()) + .into_iter() + .flatten() + .flat_map(|item| item.transparent_alias(generic_path.generics(), library)); + let erased_type = erased_types.next()?; + if let Some(other_erased_type) = erased_types.next() { + warn!( + "Found multiple erased types for {:?}: {:?} vs. {:?}", + generic_path, erased_type, other_erased_type + ); + return None; + } + Some(erased_type) + } + Type::Primitive(_) => None, + Type::Array(ty, expr) => Some(Type::Array( + Box::new(ty.transparent_alias(library)?), + expr.clone(), + )), + Type::FuncPtr { + ret, + args, + is_nullable, + never_return, + } => { + let new_ret = ret.transparent_alias(library); + let new_args: Vec<_> = args.iter().map(|(_, ty)| ty.transparent_alias(library)).collect(); + (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { + Type::FuncPtr { + ret: Box::new(new_ret.unwrap_or_else(|| ret.as_ref().clone())), + args: new_args + .into_iter() + .zip(args) + .map(|(new_arg, (name, arg))| { + let new_arg = new_arg.unwrap_or_else(|| arg.clone()); + (name.clone(), new_arg) + }) + .collect(), + is_nullable: *is_nullable, + never_return: *never_return, + } + }) + } + } + } + pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type { match *self { Type::Ptr { @@ -705,7 +767,7 @@ impl Type { out.items.insert(path.clone()); for item in &items { - item.deref().add_dependencies(library, out); + item.add_dependencies(library, out); } for item in items { out.order.push(item); @@ -751,8 +813,7 @@ impl Type { let path = generic.path(); if let Some(items) = library.get_items(path) { for item in items { - item.deref() - .instantiate_monomorph(generic.generics(), library, out); + item.instantiate_monomorph(generic.generics(), library, out); } } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e775a4e8..7c1440ea 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -113,6 +113,13 @@ impl Typedef { pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) { self.aliased.mangle_paths(monomorphs); } + + pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { + Some(Typedef { + aliased: self.aliased.transparent_alias(library)?, + ..self.clone() + }) + } } impl Item for Typedef { @@ -156,6 +163,16 @@ impl Item for Typedef { &self.generic_params } + fn transparent_alias(&self, generics: &[GenericArgument], library: &Library) -> Option { + if self.is_generic() { + let mappings = self.generic_params.call(self.path.name(), generics); + let aliased = self.aliased.specialize(&mappings); + aliased.transparent_alias(library) + } else { + self.aliased.transparent_alias(library) + } + } + 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 9c425837..2975f06b 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, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -162,6 +162,10 @@ impl Item for Union { &self.generic_params } + fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + None + } + 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/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index 065bade2..6b693ee3 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -159,12 +159,7 @@ pub trait LanguageBackend: Sized { fn write_items(&mut self, out: &mut SourceWriter, b: &Bindings) { for item in &b.items { - if item - .deref() - .annotations() - .bool("no-export") - .unwrap_or(false) - { + if item.annotations().bool("no-export").unwrap_or(false) { continue; } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f..95e3086a 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -95,7 +95,7 @@ impl Library { if let Some(items) = self.get_items(&path) { if dependencies.items.insert(path) { for item in &items { - item.deref().add_dependencies(&self, &mut dependencies); + item.add_dependencies(&self, &mut dependencies); } for item in items { dependencies.order.push(item); @@ -390,6 +390,23 @@ impl Library { } } + fn erase_types(&mut self) { + let mut structs = HashMap::new(); + let mut i = 0; + self.structs.for_all_items(|x| { + x.resolve_transparent_aliases(self).map(|alias| { + structs.insert(i, alias); + }); + i += 1; + }); + + let mut i = 0; + self.structs.for_all_items_mut(|x| { + structs.remove(&i).map(|alias| *x = alias); + i += 1; + }); + } + fn instantiate_monomorphs(&mut self) { // Collect a list of monomorphs let mut monomorphs = Monomorphs::default(); diff --git a/tests/tests.rs b/tests/tests.rs index eebabefb..de77547c 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -331,6 +331,18 @@ fn test_file(name: &'static str, filename: &'static str) { // Run tests in deduplication priority order. C++ compatibility tests are run first, // otherwise we would lose the C++ compiler run if they were deduplicated. let mut cbindgen_outputs = HashSet::new(); + + run_compile_test( + name, + test, + tmp_dir, + Language::Cxx, + /* cpp_compat = */ false, + None, + &mut HashSet::new(), + false, + ); + for cpp_compat in &[true, false] { for style in &[Style::Type, Style::Tag, Style::Both] { run_compile_test( @@ -346,17 +358,6 @@ fn test_file(name: &'static str, filename: &'static str) { } } - run_compile_test( - name, - test, - tmp_dir, - Language::Cxx, - /* cpp_compat = */ false, - None, - &mut HashSet::new(), - false, - ); - // `Style::Both` should be identical to `Style::Tag` for Cython. let mut cbindgen_outputs = HashSet::new(); for style in &[Style::Type, Style::Tag] { From 51b2d4ea0847678ebd40f19fca23ed5c98b8882c Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Mon, 4 Nov 2024 10:38:59 -0700 Subject: [PATCH 02/13] all seems to work now --- src/bindgen/ir/constant.rs | 2 +- src/bindgen/ir/enumeration.rs | 2 +- src/bindgen/ir/function.rs | 25 ++++- src/bindgen/ir/generic_path.rs | 7 +- src/bindgen/ir/global.rs | 2 +- src/bindgen/ir/item.rs | 2 +- src/bindgen/ir/opaque.rs | 25 ++++- src/bindgen/ir/structure.rs | 34 +++++- src/bindgen/ir/ty.rs | 69 +++++++++--- src/bindgen/ir/typedef.rs | 13 +-- src/bindgen/ir/union.rs | 2 +- src/bindgen/library.rs | 45 +++++++- src/bindgen/parser.rs | 3 +- tests/rust/transparent_typedef.rs | 169 ++++++++++++++++++++++++++++++ 14 files changed, 357 insertions(+), 43 deletions(-) create mode 100644 tests/rust/transparent_typedef.rs diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 477f2d9c..3cf162cc 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -603,7 +603,7 @@ impl Item for Constant { fn generic_params(&self) -> &GenericParams { GenericParams::empty() } - fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { None } } diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 84acb084..0a94c35e 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -501,7 +501,7 @@ impl Item for Enum { &self.generic_params } - fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { None } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index f25d2f88..e91465d0 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -9,7 +9,7 @@ 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, GenericParams, Documentation, GenericPath, Path, Type}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; @@ -143,6 +143,29 @@ impl Function { } } + pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { + // TODO: Dedup with `Type::FuncPtr` case in `Type::transparent_alias` + let empty = GenericParams::empty(); + let new_ret = self.ret.transparent_alias(library, empty); + let new_args: Vec<_> = self.args.iter().map(|arg| arg.ty.transparent_alias(library, empty)).collect(); + (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { + Function { + ret: new_ret.unwrap_or_else(|| self.ret.clone()), + args: new_args + .into_iter() + .zip(&self.args) + .map(|(ty, arg)| { + FunctionArgument { + ty: ty.unwrap_or_else(|| arg.ty.clone()), + ..arg.clone() + } + }) + .collect(), + ..self.clone() + } + }) + } + pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { self.ret.resolve_declaration_types(resolver); for arg in &mut self.args { diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 4610641c..bd938e2a 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -25,11 +25,11 @@ pub struct GenericParam { } impl GenericParam { - pub fn new_type_param(name: &str) -> Self { + pub fn new_type_param(name: &str, default: Option) -> Self { GenericParam { name: Path::new(name), ty: GenericParamType::Type, - default: None, + default, } } @@ -80,6 +80,9 @@ impl GenericParam { pub fn name(&self) -> &Path { &self.name } + pub fn default(&self) -> Option<&GenericArgument> { + self.default.as_ref() + } } #[derive(Default, Debug, Clone)] diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 45d9cd87..7099e1d6 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -110,7 +110,7 @@ impl Item for Static { GenericParams::empty() } - fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { None } diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 68a44b44..e57f4988 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -43,7 +43,7 @@ pub trait Item { !self.generic_params().is_empty() } - fn transparent_alias(&self, generics: &[GenericArgument], _library: &Library) -> Option; + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option; fn rename_for_config(&mut self, _config: &Config) {} fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) {} fn instantiate_monomorph( diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4d90ea44..fadcf6b2 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -95,8 +95,29 @@ impl Item for OpaqueItem { &self.generic_params } - fn transparent_alias(&self, generics: &[GenericArgument], _library: &Library) -> Option { - None // TODO! + fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { + // NOTE: Our caller already resolved the params, no need to resolve them again here. + if !self.is_generic() { + return None; + } + let Some(GenericArgument::Type(ty)) = args.first() else { + return None; + }; + let ty = 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" => ty.make_nullable().or_else(|| ty.make_zeroable(true))?, + _ => return None, + }; + let mappings = self.generic_params.call(self.path.name(), args); + Some(ty.specialize(&mappings)) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 9be6f8ce..78ab47e8 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -10,7 +10,7 @@ use crate::bindgen::config::{Config, Language, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, Item, + AnnotationSet, Cfg, Constant, GenericParam, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; @@ -193,8 +193,28 @@ impl Struct { } pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { - let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library)).collect(); - if types.iter().all(Option::is_none) { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.as_ref().unwrap_or(params); + let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library, params)).collect(); + if new_params.is_none() && types.iter().all(Option::is_none) { return None; } let fields = types.into_iter().zip(&self.fields).map(|(ty, field)| { @@ -204,6 +224,7 @@ impl Struct { } }).collect(); Some(Struct { + generic_params: new_params.unwrap_or(self.generic_params.clone()), fields, ..self.clone() }) @@ -329,8 +350,11 @@ impl Item for Struct { &self.generic_params } - fn transparent_alias(&self, generics: &[GenericArgument], library: &Library) -> Option { - self.as_typedef().and_then(|t| t.transparent_alias(generics, library)) + fn transparent_alias(&self, library: &Library, args: &[GenericArgument], params: &GenericParams) -> Option { + let Some(typedef) = self.as_typedef() else { + return None; + }; + typedef.transparent_alias(library, args, params).or(Some(typedef.aliased)) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 7949eac9..8eea27bb 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -627,8 +627,32 @@ impl Type { } } + pub fn transparent_alias_for_path(&self, path: &Path, generics: &[GenericArgument], library: &Library, params: &GenericParams) -> Option { + let items = library.get_items(path); + if items.is_none() { + warn!("Unknown type {path:?}"); + return None; + } + let mut erased_types = items + .into_iter() + .flatten() + .flat_map(|item| item.transparent_alias(library, generics, params)); + let Some(erased_type) = erased_types.next() else { + return None; + }; + if let Some(other_erased_type) = erased_types.next() { + warn!( + "Found multiple erased types for {:?}: {:?} vs. {:?}", + path, erased_type, other_erased_type + ); + return None; + } + // The type we just resolved may itself be transparent... recurse + erased_type.transparent_alias(library, params).or(Some(erased_type)) + } + /// If this type is transparent, recursively replace it with whatever type it aliases. - pub fn transparent_alias(&self, library: &Library) -> Option { + pub fn transparent_alias(&self, library: &Library, params: &GenericParams) -> Option { match self { Type::Ptr { ty, @@ -636,30 +660,41 @@ impl Type { is_nullable, is_ref, } => Some(Type::Ptr { - ty: Box::new(ty.transparent_alias(library)?), + ty: Box::new(ty.transparent_alias(library, params)?), is_const: *is_const, is_nullable: *is_nullable, is_ref: *is_ref, }), Type::Path(generic_path) => { - let mut erased_types = library - .get_items(generic_path.path()) - .into_iter() - .flatten() - .flat_map(|item| item.transparent_alias(generic_path.generics(), library)); - let erased_type = erased_types.next()?; - if let Some(other_erased_type) = erased_types.next() { - warn!( - "Found multiple erased types for {:?}: {:?} vs. {:?}", - generic_path, erased_type, other_erased_type - ); + let path = generic_path.path(); + if params.0.iter().any(|p| p.name() == path) { return None; } - Some(erased_type) + // process the generics first -- they may change even if this type isn't transparent + let generics = generic_path.generics(); + let new_generics: Vec<_> = generics.iter().map(|arg| match arg { + GenericArgument::Type(ty) => { + let new_ty = ty.transparent_alias(library, params)?; + Some(GenericArgument::Type(new_ty)) + } + _ => None + }).collect(); + let new_generics = new_generics.iter().any(Option::is_some).then(|| -> Vec<_> { + new_generics.into_iter().zip(generics).map(|(new_arg, arg)| { + new_arg.unwrap_or_else(|| arg.clone()) + }).collect() + }); + let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); + let new_ty = self.transparent_alias_for_path(path, generics, library, params); + if new_ty.is_some() { + new_ty + } else { + new_generics.map(|g| Type::Path(GenericPath::new(path.clone(), g))) + } } Type::Primitive(_) => None, Type::Array(ty, expr) => Some(Type::Array( - Box::new(ty.transparent_alias(library)?), + Box::new(ty.transparent_alias(library, params)?), expr.clone(), )), Type::FuncPtr { @@ -668,8 +703,8 @@ impl Type { is_nullable, never_return, } => { - let new_ret = ret.transparent_alias(library); - let new_args: Vec<_> = args.iter().map(|(_, ty)| ty.transparent_alias(library)).collect(); + let new_ret = ret.transparent_alias(library, params); + let new_args: Vec<_> = args.iter().map(|(_, ty)| ty.transparent_alias(library, params)).collect(); (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { Type::FuncPtr { ret: Box::new(new_ret.unwrap_or_else(|| ret.as_ref().clone())), diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 7c1440ea..0ae8d17d 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -116,7 +116,7 @@ impl Typedef { pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { Some(Typedef { - aliased: self.aliased.transparent_alias(library)?, + aliased: self.aliased.transparent_alias(library, &self.generic_params)?, ..self.clone() }) } @@ -163,13 +163,14 @@ impl Item for Typedef { &self.generic_params } - fn transparent_alias(&self, generics: &[GenericArgument], library: &Library) -> Option { + fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { + // NOTE: We don't need to resolve params, because our caller will reprocess it. Just + // specialize the aliased type (if needed) and return it. if self.is_generic() { - let mappings = self.generic_params.call(self.path.name(), generics); - let aliased = self.aliased.specialize(&mappings); - aliased.transparent_alias(library) + let mappings = self.generic_params.call(self.path.name(), args); + Some(self.aliased.specialize(&mappings)) } else { - self.aliased.transparent_alias(library) + Some(self.aliased.clone()) } } diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 2975f06b..516aabce 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -162,7 +162,7 @@ impl Item for Union { &self.generic_params } - fn transparent_alias(&self, _generics: &[GenericArgument], _library: &Library) -> Option { + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { None } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 95e3086a..859583a6 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -63,6 +63,7 @@ impl Library { pub fn generate(mut self) -> Result { self.transfer_annotations(); self.simplify_standard_types(); + self.resolve_transparent_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)), @@ -390,19 +391,55 @@ impl Library { } } - fn erase_types(&mut self) { + fn resolve_transparent_types(&mut self) { let mut structs = HashMap::new(); let mut i = 0; self.structs.for_all_items(|x| { - x.resolve_transparent_aliases(self).map(|alias| { + if let Some(alias) = x.resolve_transparent_aliases(self) { structs.insert(i, alias); - }); + } i += 1; }); let mut i = 0; self.structs.for_all_items_mut(|x| { - structs.remove(&i).map(|alias| *x = alias); + if let Some(alias) = structs.remove(&i) { + *x = alias; + } + i += 1; + }); + + let mut typedefs = HashMap::new(); + let mut i = 0; + self.typedefs.for_all_items(|x| { + if let Some(alias) = x.resolve_transparent_aliases(self) { + typedefs.insert(i, alias); + } + i += 1; + }); + + let mut i = 0; + self.typedefs.for_all_items_mut(|x| { + if let Some(alias) = typedefs.remove(&i) { + *x = alias; + } + i += 1; + }); + + let mut functions = HashMap::new(); + let mut i = 0; + self.functions.iter().for_each(|x| { + if let Some(alias) = x.resolve_transparent_aliases(self) { + functions.insert(i, alias); + } + i += 1; + }); + + let mut i = 0; + self.functions.iter_mut().for_each(|x| { + if let Some(alias) = functions.remove(&i) { + *x = alias; + } i += 1; }); } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index eb2ef2dc..1c7778ac 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -443,7 +443,7 @@ impl Parse { let path = Path::new(path); let generic_params: Vec<_> = generic_params .into_iter() - .map(GenericParam::new_type_param) + .map(|name| GenericParam::new_type_param(name, None)) .collect(); self.opaque_items.try_insert(OpaqueItem::new( path, @@ -462,6 +462,7 @@ impl Parse { add_opaque("Result", vec!["T", "E"]); add_opaque("Option", vec!["T"]); add_opaque("NonNull", vec!["T"]); + add_opaque("NonZero", vec!["T"]); add_opaque("Vec", vec!["T"]); add_opaque("HashMap", vec!["K", "V", "Hasher"]); add_opaque("BTreeMap", vec!["K", "V"]); diff --git a/tests/rust/transparent_typedef.rs b/tests/rust/transparent_typedef.rs new file mode 100644 index 00000000..93e0f42a --- /dev/null +++ b/tests/rust/transparent_typedef.rs @@ -0,0 +1,169 @@ +use std::num::NonZero; +use std::ptr::NonNull; + +#[repr(C)] +pub struct Struct { + field: T, +} + +/// cbindgen:transparent-typedef +#[repr(transparent)] +pub struct Transparent { + field: T, + _phantom: std::marker::PhantomData

, +} + +pub type Typedef> = Transparent; + +/// cbindgen:transparent-typedef +pub type Alias> = Transparent; + +#[repr(C)] +pub struct FullyTransparent1> { + a: Alias, + n: NonNull, + t: Transparent, + + ai: Alias, + ni: NonNull, + ti: Transparent, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct NotTransparent1<'a, E = Option> { + o: &'a Option, + s: &'a Struct, + t: &'a Typedef, + + oi: &'a Option, + si: &'a Struct, + ti: &'a Typedef, +} + +#[no_mangle] +pub extern "C" fn test1( + a: Struct, + b: Typedef, + c: &Option, + d: Transparent, + e: Alias, +) {} + +#[no_mangle] +pub extern "C" fn root1( + a: FullyTransparent1>, + s: NotTransparent1>) {} + +#[repr(C)] +pub struct FullyTransparent2>> { + aa: Alias>, + an: Alias>, + at: Alias>, + na: NonNull>, + nn: NonNull>, + nt: NonNull>, + on: Option>, + ta: Transparent>, + tn: Transparent>, + tt: Transparent>, + + aai: Alias>, + ani: Alias>, + ati: Alias>, + nai: NonNull>, + nni: NonNull>, + nti: NonNull>, + oni: Option>, + tai: Transparent>, + tni: Transparent>, + tti: Transparent>, +} + +// Option only gets erased if T is NonNull or NonZero; use references so it still compiles. +#[repr(C)] +pub struct PartlyTransparent2<'a, E> { + ao: &'a Alias>, + aS: &'a Alias>, + at: &'a Alias>, + no: &'a NonNull>, + ns: &'a NonNull>, + nt: &'a NonNull>, + + aoi: &'a Alias>, + asi: &'a Alias>, + ati: &'a Alias>, + noi: &'a NonNull>, + nsi: &'a NonNull>, + nti: &'a NonNull>, +} + +// Use references so it still compiles. +#[repr(C)] +pub struct NotTransparent2<'a, E = Option>> { + oo: &'a Option>, + os: &'a Option>, + so: &'a Struct>, + ss: &'a Struct>, + + ooi: &'a Option>, + osi: &'a Option>, + soi: &'a Struct>, + ssi: &'a Struct>, +} + +#[no_mangle] +pub extern "C" fn root2( + a: FullyTransparent2>>, + s: PartlyTransparent2>>, + n: NotTransparent2>>) {} + +#[repr(C)] +pub struct FullyTransparentMany>>>>> { + ont: Option>>, + otn: Option>>, + ton: Transparent>>, + + // One erasable quadruple + totn: Transparent>>>, + + onti: Option>>, + otni: Option>>, + toni: Transparent>>, + + // One erasable quadruple + totni: Transparent>>>, +} + +#[repr(C)] +pub struct PartlyTransparentMany<'a, E> { + // A few triples + tao: &'a Transparent>>, + toa: &'a Transparent>>, + ota: &'a Option>>, + tas: &'a Transparent>>, + tsa: &'a Transparent>>, + sta: &'a Struct>>, + + // Two quadruples + toat: &'a Transparent>>>, + tsat: &'a Transparent>>>, + + // A few triples + taoi: &'a Transparent>>, + toai: &'a Transparent>>, + otai: &'a Option>>, + tasi: &'a Transparent>>, + tsai: &'a Transparent>>, + stai: &'a Struct>>, + + // Two quadruples + toati: &'a Transparent>>>, + tsati: &'a Transparent>>>, +} + +#[no_mangle] +pub extern "C" fn root_many( + a: FullyTransparentMany>>>, + b: PartlyTransparentMany>>>, +) {} From 9a554ae67fc0948151230c85a634555b825fe4bf Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Tue, 5 Nov 2024 03:59:55 -0800 Subject: [PATCH 03/13] added the rest of the feature --- docs.md | 103 +++++++++++++++++++++++++++++------- src/bindgen/builder.rs | 2 +- src/bindgen/ir/opaque.rs | 2 +- src/bindgen/ir/typedef.rs | 21 +++++--- src/bindgen/library.rs | 2 - src/bindgen/parser.rs | 107 +++++++++++++++++++++++++------------- tests/rust/transparent.rs | 70 ++++++++++++++++++++++++- 7 files changed, 240 insertions(+), 67 deletions(-) diff --git a/docs.md b/docs.md index c8ce9f4f..ad5dcc18 100644 --- a/docs.md +++ b/docs.md @@ -299,7 +299,76 @@ fn bar() -> Foo { .. } // Will be emitted as `struct foo bar();` ### Struct Annotations -* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming. +* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output + struct. These names will be output verbatim, and are not eligible for renaming. + +* transparent-typedef -- when emitting the typedef for a transparent struct, mark it as + transparent. All references to the struct will be replaced with the type of its underlying NZST + field, effectively making the struct invisible on the FFI side. For example, consider the + following Rust code: + + ```rust + #[repr(transparent)] + pub struct Handle { + ptr: NonNull, + } + + pub struct Foo { } + + #[no_mangle] + pub extern "C" fn foo_operation(foo: Option>) { } + ``` + + By default, the exported C++ code would fail to compile, because the function takes `Option<...>` + (which is an opaque type) by value: + + ```cpp + template + struct Option; + + template + using Handle = T; + + struct Foo; + + void foo_operation(Option> foo); + ``` + + If we annotate `Handle` with `transparent-typedef` (leaving the rest of the code unchanged): + ```rust + /// cbindgen:transparent-typedef + #[repr(transparent)] + pub struct Handle { + ptr: NonNull, + } + ``` + + Then cbindgen is able to simplify the exported C++ code to just: + ```cpp + struct Foo; + + void foo_operation(Foo* foo); + ``` + + NOTE: This annotation does _NOT_ affect user-defined type aliases for transparent structs. If we + we adjust the previous example to use a type alias: + + ```rust + type NullableFooHandle = Option>; + + #[no_mangle] + pub extern "C" fn foo_operation(foo: NullableFooHandle) { } + ``` + + Then the exported code will use it as expected: + + ```cpp + struct Foo; + + using NullableFooHandle = Foo*; + + void foo_operation(NullableFooHandle foo); + ``` The rest are just local overrides for the same options found in the cbindgen.toml: @@ -316,27 +385,25 @@ The rest are just local overrides for the same options found in the cbindgen.tom / etc(if any). The idea is for this to be used to annotate the operator with attributes, for example: -```rust -/// cbindgen:eq-attributes=MY_ATTRIBUTES -#[repr(C)] -pub struct Foo { .. } -``` - -Will generate something like: + ```rust + /// cbindgen:eq-attributes=MY_ATTRIBUTES + #[repr(C)] + pub struct Foo { .. } + ``` -``` - MY_ATTRIBUTES bool operator==(const Foo& other) const { - ... - } -``` + Will generate something like: -Combined with something like: + ``` + MY_ATTRIBUTES bool operator==(const Foo& other) const { + ... + } + ``` -``` -#define MY_ATTRIBUTES [[nodiscard]] -``` + Combined with something like: -for example. + ``` + #define MY_ATTRIBUTES [[nodiscard]] + ``` ### Enum Annotations diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index d47919b9..a649a0fc 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -368,7 +368,7 @@ impl Builder { let mut result = Parse::new(); if self.std_types { - result.add_std_types(); + result.add_std_types(self.config.language); } for x in &self.srcs { diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index fadcf6b2..762f00ae 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -112,7 +112,7 @@ impl Item for OpaqueItem { is_ref: false, }) } - "NonZero" => return ty.make_zeroable(false), + "NonZero" => return ty.make_zeroable(false), "Option" => ty.make_nullable().or_else(|| ty.make_zeroable(true))?, _ => return None, }; diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 0ae8d17d..0162682e 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -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()); @@ -164,14 +167,16 @@ impl Item for Typedef { } fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { - // NOTE: We don't need to resolve params, because our caller will reprocess it. Just - // specialize the aliased type (if needed) and return it. - if self.is_generic() { - let mappings = self.generic_params.call(self.path.name(), args); - Some(self.aliased.specialize(&mappings)) - } else { - Some(self.aliased.clone()) - } + matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { + // NOTE: We don't need to resolve params, because our caller will reprocess it. Just + // specialize the aliased type (if needed) and return it. + if self.is_generic() { + let mappings = self.generic_params.call(self.path.name(), args); + self.aliased.specialize(&mappings) + } else { + self.aliased.clone() + } + }) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 859583a6..cae1840a 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -61,8 +61,6 @@ impl Library { } pub fn generate(mut self) -> Result { - self.transfer_annotations(); - self.simplify_standard_types(); self.resolve_transparent_types(); match self.config.function.sort_by.unwrap_or(self.config.sort_by) { diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 1c7778ac..235a817e 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -12,10 +12,10 @@ 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, + AnnotationSet, AnnotationValue, Cfg, Constant, Documentation, Enum, Function, GenericPath, GenericArgument, GenericParam, GenericParams, ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, }; use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemHelpers}; @@ -438,40 +438,77 @@ impl Parse { } } - pub fn add_std_types(&mut self) { - let mut add_opaque = |path: &str, generic_params: Vec<&str>| { - let path = Path::new(path); - let generic_params: Vec<_> = generic_params - .into_iter() - .map(|name| GenericParam::new_type_param(name, None)) - .collect(); - self.opaque_items.try_insert(OpaqueItem::new( - path, - GenericParams(generic_params), - None, - AnnotationSet::new(), - Documentation::none(), - )) - }; + fn create_generic_params(param_names: Vec<&str>) -> Vec { + param_names + .iter() + .map(|name| GenericParam::new_type_param(name, None)) + .collect() + } + + fn add_opaque(&mut self, path: &str, generic_params: Vec<&str>) { + self.opaque_items.try_insert(OpaqueItem::new( + Path::new(path), + GenericParams(Self::create_generic_params(generic_params)), + None, + AnnotationSet::new(), + Documentation::none(), + )); + } + + fn add_transparent_typedef(&mut self, path: &str, aliased: Type, generic_params: Vec<&str>) { + let mut annotations = AnnotationSet::new(); + annotations.add_default(Typedef::TRANSPARENT_TYPEDEF, AnnotationValue::Bool(true)); + self.typedefs.try_insert(Typedef::new( + Path::new(path), + GenericParams(Self::create_generic_params(generic_params)), + aliased, + None, + annotations, + Documentation::none(), + )); + } + + pub fn add_std_types(&mut self, language: Language) { + // Always opaque + self.add_opaque("String", vec![]); + self.add_opaque("RefCell", vec!["T"]); + self.add_opaque("Rc", vec!["T"]); + self.add_opaque("Arc", vec!["T"]); + self.add_opaque("Result", vec!["T", "E"]); + self.add_opaque("Vec", vec!["T"]); + self.add_opaque("HashMap", vec!["K", "V", "Hasher"]); + self.add_opaque("BTreeMap", vec!["K", "V"]); + self.add_opaque("HashSet", vec!["T"]); + self.add_opaque("BTreeSet", vec!["T"]); + self.add_opaque("LinkedList", vec!["T"]); + self.add_opaque("VecDeque", vec!["T"]); + + // Registered as opaque, but potentially transparent (see OpaqueItem::transparent_alias). + self.add_opaque("Option", vec!["T"]); + self.add_opaque("NonNull", vec!["T"]); + self.add_opaque("NonZero", vec!["T"]); + + // Opaque in C++ but transparent in C + let tpath = Type::Path(GenericPath::new(Path::new("T"), vec![])); + if language == Language::Cxx { + self.add_opaque("Box", vec!["T"]); + self.add_opaque("ManuallyDrop", vec!["T"]); + self.add_opaque("MaybeUninit", vec!["T"]); + self.add_opaque("Pin", vec!["T"]); + } else { + // NOTE: Box acts like NonNull in C + let generics = vec![GenericArgument::Type(tpath.clone())]; + let alias = Type::Path(GenericPath::new(Path::new("NonNull"), generics)); + self.add_transparent_typedef("Box", alias, vec!["T"]); + self.add_transparent_typedef("ManuallyDrop", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("MaybeUninit", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("Pin", tpath.clone(), vec!["T"]); + } - add_opaque("String", vec![]); - add_opaque("Box", vec!["T"]); - add_opaque("RefCell", vec!["T"]); - add_opaque("Rc", vec!["T"]); - add_opaque("Arc", vec!["T"]); - add_opaque("Result", vec!["T", "E"]); - add_opaque("Option", vec!["T"]); - add_opaque("NonNull", vec!["T"]); - add_opaque("NonZero", vec!["T"]); - add_opaque("Vec", vec!["T"]); - add_opaque("HashMap", vec!["K", "V", "Hasher"]); - add_opaque("BTreeMap", vec!["K", "V"]); - add_opaque("HashSet", vec!["T"]); - add_opaque("BTreeSet", vec!["T"]); - add_opaque("LinkedList", vec!["T"]); - add_opaque("VecDeque", vec!["T"]); - add_opaque("ManuallyDrop", vec!["T"]); - add_opaque("MaybeUninit", vec!["T"]); + // Always transparent + self.add_transparent_typedef("Cell", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("SyncUnsafeCell", tpath.clone(), vec!["T"]); + self.add_transparent_typedef("UnsafeCell", tpath.clone(), vec!["T"]); } pub fn extend_with(&mut self, other: &Parse) { diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index e35200cf..fb812e33 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -16,6 +16,10 @@ struct TransparentComplexWrappingStructure { only_field: DummyStruct } #[repr(transparent)] struct TransparentPrimitiveWrappingStructure { only_field: u32 } +// Transparent struct wrapping a pointer +#[repr(transparent)] +struct TransparentPointerWrappingStructure { only_field: *const u32 } + // Transparent struct wrapper with a marker wrapping a struct. #[repr(transparent)] struct TransparentComplexWrapper { @@ -53,10 +57,18 @@ impl TransparentPrimitiveWithAssociatedConstants { }; } +struct StructWithAssociatedConstantInImpl { } + +impl StructWithAssociatedConstantInImpl { + pub const STRUCT_TEN: TransparentPrimitiveWrappingStructure = + TransparentPrimitiveWrappingStructure { only_field: 10 }; +} + enum EnumWithAssociatedConstantInImpl { A } impl EnumWithAssociatedConstantInImpl { - pub const TEN: TransparentPrimitiveWrappingStructure = TransparentPrimitiveWrappingStructure { only_field: 10 }; + pub const ENUM_TEN: TransparentPrimitiveWrappingStructure = + TransparentPrimitiveWrappingStructure { only_field: 10 }; } #[no_mangle] @@ -69,5 +81,59 @@ pub extern "C" fn root( f: TransparentPrimitiveWrapper, g: TransparentPrimitiveWithAssociatedConstants, h: TransparentEmptyStructure, - i: EnumWithAssociatedConstantInImpl, + i: TransparentPointerWrappingStructure, + j: StructWithAssociatedConstantInImpl, + k: EnumWithAssociatedConstantInImpl, +) { } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentNonNullPointerWrappingStruct { only_field: NonNull } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentOptionalNonNullPointerWrappingStruct { only_field: Option> } + +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentWrappingAnotherTransparentStruct { only_field: TransparentPrimitiveWrappingStructure } + +/// cbindgen:transparent-typedef +#[repr(transparent)] +struct ErasedTransparentWrappingTransparentNonNullPointerStruct { only_field: ErasedTransparentNonNullPointerWrappingStruct } + +// Transparent structure wrapping another type +#[repr(transparent)] +/// cbindgen:transparent-typedef +struct ErasedTransparentStructWrappingAnotherType { only_field: T } + +type TransparentIntStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentComplexStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentTransparentStruct = ErasedTransparentStructWrappingAnotherType; +type TransparentNonNullStruct = ErasedTransparentStructWrappingAnotherType>; +type TransparentOptionNonNullStruct = ErasedTransparentStructWrappingAnotherType>>; + +/// cbindgen:transparent-typedef +type ErasedTransparentIntStruct = ErasedTransparentStructWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentComplexStruct = ErasedTransparentStructWrappingAnotherType; +/// cbindgen:transparent-typedef +type ErasedTransparentOptionNonNullStruct = ErasedTransparentStructWrappingAnotherType>>; + +#[no_mangle] +pub extern "C" fn erased_root( + a: ErasedTransparentNonNullPointerWrappingStruct, + b: ErasedTransparentOptionalNonNullPointerWrappingStruct, + c: ErasedTransparentWrappingAnotherTransparentStruct, + d: ErasedTransparentWrappingTransparentNonNullPointerStruct, + e: ErasedTransparentStructWrappingAnotherType, + f: ErasedTransparentStructWrappingAnotherType, + g: ErasedTransparentStructWrappingAnotherType, + h: ErasedTransparentStructWrappingAnotherType, + i: ErasedTransparentIntStruct, + j: TransparentIntStruct, + k: TransparentComplexStruct, + l: TransparentTransparentStruct, + m: TransparentNonNullStruct, + n: TransparentOptionNonNullStruct, ) { } From 3c306123266df63eaacc66744a23f733a6cab3c3 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Tue, 5 Nov 2024 09:30:01 -0800 Subject: [PATCH 04/13] debugged specialization issues --- src/bindgen/ir/opaque.rs | 31 +++++++++--- src/bindgen/ir/structure.rs | 9 ++-- src/bindgen/ir/ty.rs | 79 ++++++++++++++++++++++++++----- src/bindgen/ir/typedef.rs | 32 +++++++++++-- tests/rust/nonnull.rs | 5 +- tests/rust/transparent_typedef.rs | 71 +++++++++++++++++++++++++-- 6 files changed, 193 insertions(+), 34 deletions(-) diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 762f00ae..de1ef71b 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::borrow::Cow; + use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; @@ -95,7 +97,7 @@ impl Item for OpaqueItem { &self.generic_params } - fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { + fn transparent_alias(&self, library: &Library, args: &[GenericArgument], params: &GenericParams) -> Option { // NOTE: Our caller already resolved the params, no need to resolve them again here. if !self.is_generic() { return None; @@ -103,21 +105,36 @@ impl Item for OpaqueItem { let Some(GenericArgument::Type(ty)) = args.first() else { return None; }; + // We have to specialize before resolving, in case the args themselves get resolved + // Option>> + let ty = if self.is_generic() { + let Some(GenericArgument::Type(new_ty)) = args.first() else { + return None; + }; + warn!("Specializing {ty:#?} as {new_ty:#?}"); + new_ty + } else { + ty + }; + //let resolved_ty = ty.transparent_alias(library, params); + //let ty = resolved_ty.map_or_else(|| Cow::Borrowed(ty), |resolved| Cow::Owned(resolved)); let ty = match self.name() { "NonNull" => { - return Some(Type::Ptr { + //warn!("Processing {self:#?}"); + Type::Ptr { ty: Box::new(ty.clone()), is_const: false, is_nullable: false, is_ref: false, - }) + } } - "NonZero" => return ty.make_zeroable(false), - "Option" => ty.make_nullable().or_else(|| ty.make_zeroable(true))?, + "NonZero" => ty.make_zeroable(false)?, + "Option" => ty.make_zeroable(true).or_else(|| ty.make_nullable())?, _ => return None, }; - let mappings = self.generic_params.call(self.path.name(), args); - Some(ty.specialize(&mappings)) + Some(ty) + //let mappings = self.generic_params.call(self.path.name(), args); + //Some(ty.specialize(&mappings)).inspect(|x| warn!("specialized {:#?}\nfrom {ty:#?}\nto {x:#?}\nwith mappings {mappings:#?}", args.first())) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 78ab47e8..e5f28815 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -168,10 +168,9 @@ impl Struct { /// Attempts to convert this struct to a typedef (only works for transparent structs). pub fn as_typedef(&self) -> Option { - match self.fields.first() { - Some(field) if self.is_transparent => Some(Typedef::new_from_struct_field(self, field)), - _ => None, - } + let field = self.fields.first()?; + self.is_transparent.then(|| Typedef::new_from_struct_field(self, field)) + //.inspect(|field| warn!("FRJ replaced {self:#?}\nwith {field:#?}")) } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { @@ -354,7 +353,7 @@ impl Item for Struct { let Some(typedef) = self.as_typedef() else { return None; }; - typedef.transparent_alias(library, args, params).or(Some(typedef.aliased)) + typedef.transparent_alias(library, args, params) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 8eea27bb..68029671 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -2,14 +2,12 @@ * 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}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::utilities::IterHelpers; @@ -633,10 +631,29 @@ impl Type { warn!("Unknown type {path:?}"); return None; } + use crate::bindgen::ir::Item as _; let mut erased_types = items .into_iter() .flatten() - .flat_map(|item| item.transparent_alias(library, generics, params)); + .flat_map(|item| match item { + ItemContainer::Typedef(t) => t.transparent_alias(library, generics, params), + ItemContainer::Struct(s) => { + let t = s.as_typedef()?; + t.transparent_alias(library, generics, params) + } + ItemContainer::OpaqueItem(o) => { + // Opaque type `O` is tricky, because only certain combinations of `O` and + // `T` are transparent. Further, `T` itself may be a transparent type that must + // be resolved before we can make an accurate decision. Additionally, even if we + // ultimately decide `O` is not transparent, we still need to update `O` to + // reference a resolved `T`. For example, `Option>>` + // resolves as `i32` and `Option>` resolves as `Option`. + o.transparent_alias(library, generics, params) + } + _ => None, + }) + //.inspect(|item| warn!("FRJ: erased {self:#?}\nas {item:#?}")) + ; let Some(erased_type) = erased_types.next() else { return None; }; @@ -648,23 +665,56 @@ impl Type { return None; } // The type we just resolved may itself be transparent... recurse - erased_type.transparent_alias(library, params).or(Some(erased_type)) + erased_type.transparent_alias(library, params) + //.inspect(|x| warn!("Double erase {path:?}\nfrom {erased_type:#?}\nto{x:#?}")) + .or(Some(erased_type)) } /// If this type is transparent, recursively replace it with whatever type it aliases. pub fn transparent_alias(&self, library: &Library, params: &GenericParams) -> Option { + /* + if let Some(resolved) = self.transparent_alias_impl(library, params) + { + warn!("erased {self:#?}\nas {resolved:#?}"); + Some(resolved) + } else if generic_path.{ + // process the generics first -- they may change even if this type isn't transparent + let generics = generic_path.generics(); + let new_generics: Vec<_> = generics.iter().map(|arg| match arg { + GenericArgument::Type(ty) => { + let new_ty = ty.transparent_alias(library, params)?; + //warn!("GenericArgument::Type {ty:#?}\nerased as {new_ty:#?}"); + Some(GenericArgument::Type(new_ty)) + } + _ => None + }).collect(); + let new_generics = new_generics.iter().any(Option::is_some).then(|| -> Vec<_> { + new_generics.into_iter().zip(generics).map(|(new_arg, arg)| { + new_arg.unwrap_or_else(|| arg.clone()) + }).collect() + }); + let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); + } + } + pub fn transparent_alias_impl(&self, library: &Library, params: &GenericParams) -> Option { + warn!("Attempt to erase {self:#?}"); + */ match self { Type::Ptr { ty, is_const, is_nullable, is_ref, - } => Some(Type::Ptr { - ty: Box::new(ty.transparent_alias(library, params)?), - is_const: *is_const, - is_nullable: *is_nullable, - is_ref: *is_ref, - }), + } => { + let new_ty = ty.transparent_alias(library, params)?; + //warn!("Type::Ptr inner {ty:#?}\nerased as {new_ty:#?}"); + Some(Type::Ptr { + ty: Box::new(new_ty), + is_const: *is_const, + is_nullable: *is_nullable, + is_ref: *is_ref, + }) + } Type::Path(generic_path) => { let path = generic_path.path(); if params.0.iter().any(|p| p.name() == path) { @@ -675,6 +725,7 @@ impl Type { let new_generics: Vec<_> = generics.iter().map(|arg| match arg { GenericArgument::Type(ty) => { let new_ty = ty.transparent_alias(library, params)?; + //warn!("GenericArgument::Type {ty:#?}\nerased as {new_ty:#?}"); Some(GenericArgument::Type(new_ty)) } _ => None @@ -687,8 +738,12 @@ impl Type { let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); let new_ty = self.transparent_alias_for_path(path, generics, library, params); if new_ty.is_some() { + //warn!("Type::Path {self:#?}\nerased as {new_ty:#?}"); new_ty } else { + //if let Some(ref new_generics) = new_generics { + // warn!("Type::Path args {path:?} simplified to {new_generics:#?}"); + //} new_generics.map(|g| Type::Path(GenericPath::new(path.clone(), g))) } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 0162682e..902d3187 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -2,15 +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::collections::HashMap; - +use std::borrow::Cow; use syn::ext::IdentExt; use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, Path, Struct, Type, }; use crate::bindgen::library::Library; @@ -118,8 +117,30 @@ impl Typedef { } pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.map_or_else(|| Cow::Borrowed(params), |new_params| Cow::Owned(new_params)); + let aliased = self.aliased.transparent_alias(library, ¶ms)?; Some(Typedef { - aliased: self.aliased.transparent_alias(library, &self.generic_params)?, + aliased, + generic_params: params.into_owned(), ..self.clone() }) } @@ -168,11 +189,12 @@ impl Item for Typedef { fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { + //println!("Erasing {self:?}"); // NOTE: We don't need to resolve params, because our caller will reprocess it. Just // specialize the aliased type (if needed) and return it. if self.is_generic() { let mappings = self.generic_params.call(self.path.name(), args); - self.aliased.specialize(&mappings) + self.aliased.specialize(&mappings) } else { self.aliased.clone() } diff --git a/tests/rust/nonnull.rs b/tests/rust/nonnull.rs index 5e07c35c..5ad57f6d 100644 --- a/tests/rust/nonnull.rs +++ b/tests/rust/nonnull.rs @@ -15,5 +15,8 @@ pub struct Foo { i: Option>>, } +/// cbindgen:transparent-typedef +pub type NonNullPtr = Option>; + #[no_mangle] -pub extern "C" fn root(arg: NonNull, foo: *mut Foo, d: NonNull>) { } +pub extern "C" fn root(arg: NonNull, foo: *mut Foo, d: NonNull>, e: NonNullPtr>) { } diff --git a/tests/rust/transparent_typedef.rs b/tests/rust/transparent_typedef.rs index 93e0f42a..54563188 100644 --- a/tests/rust/transparent_typedef.rs +++ b/tests/rust/transparent_typedef.rs @@ -23,10 +23,12 @@ pub struct FullyTransparent1> { a: Alias, n: NonNull, t: Transparent, + f: extern "C" fn(a: Alias, n: NonNull) -> Transparent, ai: Alias, ni: NonNull, ti: Transparent, + fi: extern "C" fn(ai: Alias, ni: NonNull) -> Transparent, } // Option only gets erased if T is NonNull or NonZero; use references so it still compiles. @@ -35,10 +37,12 @@ pub struct NotTransparent1<'a, E = Option> { o: &'a Option, s: &'a Struct, t: &'a Typedef, + f: extern "C" fn(o: &Option, s: &Struct) -> *mut Typedef, oi: &'a Option, si: &'a Struct, ti: &'a Typedef, + fi: extern "C" fn(oi: &Option, si: &Struct) -> *mut Typedef, } #[no_mangle] @@ -67,6 +71,17 @@ pub struct FullyTransparent2>> { ta: Transparent>, tn: Transparent>, tt: Transparent>, + f: extern "C" fn( + aa: Alias>, + an: Alias>, + at: Alias>, + na: NonNull>, + nn: NonNull>, + nt: NonNull>, + on: Option>, + ta: Transparent>, + tn: Transparent>, + ) -> Transparent>, aai: Alias>, ani: Alias>, @@ -78,17 +93,35 @@ pub struct FullyTransparent2>> { tai: Transparent>, tni: Transparent>, tti: Transparent>, + fi: extern "C" fn( + aai: Alias>, + ani: Alias>, + ati: Alias>, + nai: NonNull>, + nni: NonNull>, + nti: NonNull>, + oni: Option>, + tai: Transparent>, + tni: Transparent>, + ) -> Transparent>, } // Option only gets erased if T is NonNull or NonZero; use references so it still compiles. #[repr(C)] -pub struct PartlyTransparent2<'a, E> { +pub struct PartlyTransparent2<'a, E = Option>> { ao: &'a Alias>, aS: &'a Alias>, at: &'a Alias>, no: &'a NonNull>, ns: &'a NonNull>, nt: &'a NonNull>, + f: extern "C" fn( + ao: &Alias>, + aS: &Alias>, + at: &Alias>, + no: &NonNull>, + ns: &NonNull>, + ) -> *mut NonNull>, aoi: &'a Alias>, asi: &'a Alias>, @@ -96,20 +129,37 @@ pub struct PartlyTransparent2<'a, E> { noi: &'a NonNull>, nsi: &'a NonNull>, nti: &'a NonNull>, + fi: extern "C" fn( + aoi: &Alias>, + asi: &Alias>, + ati: &Alias>, + noi: &NonNull>, + nsi: &NonNull>, + ) -> *mut NonNull>, } // Use references so it still compiles. #[repr(C)] -pub struct NotTransparent2<'a, E = Option>> { +pub struct NotTransparent2<'a, E = Option>> { oo: &'a Option>, os: &'a Option>, so: &'a Struct>, ss: &'a Struct>, + f: extern "C" fn( + oo: &Option>, + os: &Option>, + so: &Struct>, + ) -> *mut Struct>, ooi: &'a Option>, osi: &'a Option>, soi: &'a Struct>, ssi: &'a Struct>, + fi: extern "C" fn( + ooi: &Option>, + osi: &Option>, + soi: &Struct>, + ) -> *mut Struct>, } #[no_mangle] @@ -119,7 +169,7 @@ pub extern "C" fn root2( n: NotTransparent2>>) {} #[repr(C)] -pub struct FullyTransparentMany>>>>> { +pub struct FullyTransparentMany>>>>> { ont: Option>>, otn: Option>>, ton: Transparent>>, @@ -127,16 +177,29 @@ pub struct FullyTransparentMany>>>, + f: extern "C" fn( + ont: Option>>, + otn: Option>>, + ton: Transparent>>, + ) -> Transparent>>>, + onti: Option>>, otni: Option>>, toni: Transparent>>, // One erasable quadruple totni: Transparent>>>, + + fi: extern "C" fn( + onti: Option>>, + otni: Option>>, + toni: Transparent>>, + ) -> Transparent>>>, + } #[repr(C)] -pub struct PartlyTransparentMany<'a, E> { +pub struct PartlyTransparentMany<'a, E = Transparent>>> { // A few triples tao: &'a Transparent>>, toa: &'a Transparent>>, From 8e3836fd6dfa38e8c8df49b8d968cc63880714ef Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Tue, 5 Nov 2024 15:17:13 -0800 Subject: [PATCH 05/13] all items supported, all tests working now --- src/bindgen/ir/constant.rs | 13 ++++++ src/bindgen/ir/enumeration.rs | 74 ++++++++++++++++++++++++++++++- src/bindgen/ir/function.rs | 26 +++++++++++ src/bindgen/ir/global.rs | 10 +++++ src/bindgen/ir/opaque.rs | 50 +++++++++++++++++---- src/bindgen/ir/structure.rs | 42 ++++++++++++++++++ src/bindgen/ir/typedef.rs | 66 ++++++++++++++------------- src/bindgen/ir/union.rs | 46 ++++++++++++++++++- src/bindgen/library.rs | 69 ++++++++-------------------- src/bindgen/mod.rs | 1 + src/bindgen/transparent.rs | 67 ++++++++++++++++++++++++++++ tests/rust/nonnull.rs | 2 +- tests/rust/transparent_typedef.rs | 37 +++++++++------- 13 files changed, 393 insertions(+), 110 deletions(-) create mode 100644 src/bindgen/transparent.rs diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 3cf162cc..86caf427 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -18,6 +18,7 @@ use crate::bindgen::ir::{ }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::writer::SourceWriter; use crate::bindgen::Bindings; @@ -608,6 +609,18 @@ impl Item for Constant { } } +impl ResolveTransparentTypes for Constant { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // NOTE: We also need to simplify the literal initializer value to match the underlying + // type, but that is true for all transparent structs (not just transparent-typedef + // structs), and is handled by the `write` method below. + Some(Constant { + ty: self.ty.transparent_alias(library, GenericParams::empty())?, + ..self.clone() + }) + } +} + impl Constant { pub fn write_declaration( &self, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 0a94c35e..3e2f58dd 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -10,7 +10,7 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field, + AnnotationSet, AnnotationValue, Cfg, ConditionWrite, GenericParam, DeprecatedNoteKind, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr, ReprStyle, Struct, ToCondition, Type, }; @@ -20,6 +20,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::writer::{ListType, SourceWriter}; #[allow(clippy::large_enum_variant)] @@ -645,6 +646,77 @@ impl Item for Enum { } } +impl ResolveTransparentTypes for Enum { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.as_ref().unwrap_or(params); + let mut skip_inline_tag_field = Self::inline_tag_field(&self.repr); + let variants: Vec<_> = self.variants.iter().map(|v| match v.body { + VariantBody::Body { ref name, ref body, inline, inline_casts } => { + let fields: Vec<_> = body.fields.iter().map(|f| { + // Ignore the inline Tag field, if any (it's always first) + if skip_inline_tag_field { + skip_inline_tag_field = false; + None + } else { + Some(Field { + ty: f.ty.transparent_alias(library, params)?, + ..f.clone() + }) + } + }).collect(); + + fields.iter().any(Option::is_some).then(|| { + EnumVariant { + body: VariantBody::Body { + name: name.clone(), + body: Struct { + fields: fields.into_iter().zip(&body.fields).map(|(new_field, field)| { + new_field.unwrap_or_else(|| field.clone()) + }).collect(), + ..body.clone() + }, + inline, + inline_casts, + }, + ..v.clone() + } + }) + } + VariantBody::Empty(..) => None, + }).collect(); + + if new_params.is_none() && variants.iter().all(Option::is_none) { + return None; + } + Some(Enum { + generic_params: new_params.unwrap_or(self.generic_params.clone()), + variants: variants.into_iter().zip(&self.variants).map(|(new_variant, variant)| { + new_variant.unwrap_or_else(|| variant.clone()) + }).collect(), + ..self.clone() + }) + } +} + impl Enum { /// Emit the tag enum and convenience methods for it. /// For enums with data this is only a part of the output, diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index e91465d0..d9b59e23 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -14,6 +14,7 @@ use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -242,6 +243,31 @@ impl Function { } } +impl ResolveTransparentTypes for Function { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // TODO: Dedup with `Type::FuncPtr` case in `Type::transparent_alias` + let empty = GenericParams::empty(); + let new_ret = self.ret.transparent_alias(library, empty); + let new_args: Vec<_> = self.args.iter().map(|arg| arg.ty.transparent_alias(library, empty)).collect(); + (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { + Function { + ret: new_ret.unwrap_or_else(|| self.ret.clone()), + args: new_args + .into_iter() + .zip(&self.args) + .map(|(ty, arg)| { + FunctionArgument { + ty: ty.unwrap_or_else(|| arg.ty.clone()), + ..arg.clone() + } + }) + .collect(), + ..self.clone() + } + }) + } +} + trait SynFnArgHelpers { fn as_argument(&self) -> Result, String>; } diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 7099e1d6..68b4df4c 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -10,6 +10,7 @@ use crate::bindgen::ir::{ Type, }; use crate::bindgen::library::Library; +use crate::bindgen::transparent::ResolveTransparentTypes; #[derive(Debug, Clone)] pub struct Static { @@ -118,3 +119,12 @@ impl Item for Static { self.ty.add_dependencies(library, out); } } + +impl ResolveTransparentTypes for Static { + fn resolve_transparent_types(&self, library: &Library) -> Option { + Some(Static { + ty: self.ty.transparent_alias(library, GenericParams::empty())?, + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index de1ef71b..c5ed1dc8 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -8,12 +8,13 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + AnnotationSet, Cfg, Documentation, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, Path, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::ResolveTransparentTypes; #[derive(Debug, Clone)] pub struct OpaqueItem { @@ -97,7 +98,7 @@ impl Item for OpaqueItem { &self.generic_params } - fn transparent_alias(&self, library: &Library, args: &[GenericArgument], params: &GenericParams) -> Option { + fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { // NOTE: Our caller already resolved the params, no need to resolve them again here. if !self.is_generic() { return None; @@ -106,12 +107,11 @@ impl Item for OpaqueItem { return None; }; // We have to specialize before resolving, in case the args themselves get resolved - // Option>> - let ty = if self.is_generic() { - let Some(GenericArgument::Type(new_ty)) = args.first() else { - return None; - }; - warn!("Specializing {ty:#?} as {new_ty:#?}"); + // + // NOTE: Unlike e.g. struct or typedef, specializing opaque types is just a direct + // replacement. Otherwise, specializing `Option>` for `T` would produce + // `Option>>`. See also `OpaqueItem::instantiate_monomorph` below. + let ty = if let Some(GenericArgument::Type(new_ty)) = args.first() { new_ty } else { ty @@ -129,7 +129,10 @@ impl Item for OpaqueItem { } } "NonZero" => ty.make_zeroable(false)?, - "Option" => ty.make_zeroable(true).or_else(|| ty.make_nullable())?, + "Option" => { + warn!("Processing {self:#?}\nwith T={ty:#?}"); + ty.make_zeroable(true).or_else(|| ty.make_nullable().inspect(|n| warn!("=> became {n:#?}")))? + } _ => return None, }; Some(ty) @@ -179,3 +182,32 @@ impl Item for OpaqueItem { out.insert_opaque(self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for OpaqueItem { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + + if new_params.iter().all(Option::is_none) { + return None; + } + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + Some(OpaqueItem { + generic_params: GenericParams(params.collect()), + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index e5f28815..f86d1548 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -18,6 +18,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::SourceWriter; @@ -446,3 +447,44 @@ impl Item for Struct { out.insert_struct(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Struct { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.as_ref().unwrap_or(params); + let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library, params)).collect(); + if new_params.is_none() && types.iter().all(Option::is_none) { + return None; + } + let fields = types.into_iter().zip(&self.fields).map(|(ty, field)| { + warn!("Type of field {:?} changed from {ty:#?}\nto {:#?}", field.name, field.ty); + Field { + ty: ty.unwrap_or_else(|| field.ty.clone()), + ..field.clone() + } + }).collect(); + Some(Struct { + generic_params: new_params.unwrap_or(self.generic_params.clone()), + fields, + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 902d3187..4d904f24 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -15,6 +15,7 @@ use crate::bindgen::ir::{ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::ResolveTransparentTypes; /// A type alias that is represented as a C typedef #[derive(Debug, Clone)] @@ -115,35 +116,6 @@ impl Typedef { pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) { self.aliased.mangle_paths(monomorphs); } - - pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { - // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); - let params = new_params.map_or_else(|| Cow::Borrowed(params), |new_params| Cow::Owned(new_params)); - let aliased = self.aliased.transparent_alias(library, ¶ms)?; - Some(Typedef { - aliased, - generic_params: params.into_owned(), - ..self.clone() - }) - } } impl Item for Typedef { @@ -189,9 +161,8 @@ impl Item for Typedef { fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { - //println!("Erasing {self:?}"); - // NOTE: We don't need to resolve params, because our caller will reprocess it. Just - // specialize the aliased type (if needed) and return it. + // Specialize the aliased type (if needed) and return it. We don't need to resolve + // params, because our caller processes transparent aliases iteratively to fixpoint. if self.is_generic() { let mappings = self.generic_params.call(self.path.name(), args); self.aliased.specialize(&mappings) @@ -237,3 +208,34 @@ impl Item for Typedef { out.insert_typedef(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Typedef { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.map_or_else(|| Cow::Borrowed(params), |new_params| Cow::Owned(new_params)); + let aliased = self.aliased.transparent_alias(library, ¶ms)?; + Some(Typedef { + aliased, + generic_params: params.into_owned(), + ..self.clone() + }) + } +} diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 516aabce..9f95f1c6 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -8,13 +8,14 @@ use crate::bindgen::config::{Config, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, GenericParam, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; +use crate::bindgen::transparent::ResolveTransparentTypes; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -261,3 +262,46 @@ impl Item for Union { out.insert_union(library, self, monomorph, generic_values.to_owned()); } } + +impl ResolveTransparentTypes for Union { + fn resolve_transparent_types(&self, library: &Library) -> Option { + // Resolve any defaults in the generic params + let params = &self.generic_params; + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + let new_params = new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }); + let params = new_params.as_ref().unwrap_or(params); + let types: Vec<_> = self.fields.iter().map(|f| { + Some(Field { + ty: f.ty.transparent_alias(library, params)?, + ..f.clone() + }) + }).collect(); + if new_params.is_none() && types.iter().all(Option::is_none) { + return None; + } + let fields = types.into_iter().zip(&self.fields).map(|(new_field, field)| { + warn!("Type of field {:?} changed from {:#?}\nto {:#?}", field.name, field.ty, new_field); + new_field.unwrap_or_else(|| field.clone()) + }).collect(); + Some(Union { + generic_params: new_params.unwrap_or(self.generic_params.clone()), + fields, + ..self.clone() + }) + } +} diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index cae1840a..cdc8bdab 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -13,6 +13,7 @@ use crate::bindgen::error::Error; use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::TransparentTypeResolver; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -390,56 +391,24 @@ impl Library { } fn resolve_transparent_types(&mut self) { - let mut structs = HashMap::new(); - let mut i = 0; - self.structs.for_all_items(|x| { - if let Some(alias) = x.resolve_transparent_aliases(self) { - structs.insert(i, alias); - } - i += 1; - }); - - let mut i = 0; - self.structs.for_all_items_mut(|x| { - if let Some(alias) = structs.remove(&i) { - *x = alias; - } - i += 1; - }); - - let mut typedefs = HashMap::new(); - let mut i = 0; - self.typedefs.for_all_items(|x| { - if let Some(alias) = x.resolve_transparent_aliases(self) { - typedefs.insert(i, alias); - } - i += 1; - }); - - let mut i = 0; - self.typedefs.for_all_items_mut(|x| { - if let Some(alias) = typedefs.remove(&i) { - *x = alias; - } - i += 1; - }); - - let mut functions = HashMap::new(); - let mut i = 0; - self.functions.iter().for_each(|x| { - if let Some(alias) = x.resolve_transparent_aliases(self) { - functions.insert(i, alias); - } - i += 1; - }); - - let mut i = 0; - self.functions.iter_mut().for_each(|x| { - if let Some(alias) = functions.remove(&i) { - *x = alias; - } - i += 1; - }); + let mut resolver = TransparentTypeResolver::default(); + TransparentTypeResolver::resolve_items(&mut resolver.constants, self, &self.constants); + TransparentTypeResolver::resolve_items(&mut resolver.globals, self, &self.globals); + TransparentTypeResolver::resolve_items(&mut resolver.enums, self, &self.enums); + TransparentTypeResolver::resolve_items(&mut resolver.structs, self, &self.structs); + TransparentTypeResolver::resolve_items(&mut resolver.unions, self, &self.unions); + TransparentTypeResolver::resolve_items(&mut resolver.opaque_items, self, &self.opaque_items); + TransparentTypeResolver::resolve_items(&mut resolver.typedefs, self, &self.typedefs); + resolver.resolve_functions(self, &self.functions); + + TransparentTypeResolver::install_items(&mut resolver.constants, &mut self.constants); + TransparentTypeResolver::install_items(&mut resolver.globals, &mut self.globals); + TransparentTypeResolver::install_items(&mut resolver.enums, &mut self.enums); + TransparentTypeResolver::install_items(&mut resolver.structs, &mut self.structs); + TransparentTypeResolver::install_items(&mut resolver.unions, &mut self.unions); + TransparentTypeResolver::install_items(&mut resolver.opaque_items, &mut self.opaque_items); + TransparentTypeResolver::install_items(&mut resolver.typedefs, &mut self.typedefs); + resolver.install_functions(&mut self.functions); } fn instantiate_monomorphs(&mut self) { diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 5d788211..53953072 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -53,6 +53,7 @@ mod monomorph; mod parser; mod rename; mod reserved; +mod transparent; mod utilities; mod writer; diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs new file mode 100644 index 00000000..131b4e15 --- /dev/null +++ b/src/bindgen/transparent.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use crate::bindgen::ir::{Constant, Static, Enum, Struct, Union, OpaqueItem, Typedef, Function, Item, ItemMap}; +use crate::bindgen::library::Library; + +pub trait ResolveTransparentTypes: Sized { + fn resolve_transparent_types(&self, library: &Library) -> Option; +} + +pub type ResolvedItems = HashMap; + +/// An indirection that allows to generalize the two-stage process of resolving transparent types. +#[derive(Default)] +pub struct TransparentTypeResolver { + pub constants: ResolvedItems, + pub globals: ResolvedItems, + pub enums: ResolvedItems, + pub structs: ResolvedItems, + pub unions: ResolvedItems, + pub opaque_items: ResolvedItems, + pub typedefs: ResolvedItems, + pub functions: ResolvedItems, +} + +impl TransparentTypeResolver { + fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) { + if let Some(alias) = item.resolve_transparent_types(library) { + resolved.insert(i, alias); + } + } + + // Functions do not impl Item + pub fn resolve_functions(&mut self, library: &Library, items: &Vec) { + for (i, item) in items.into_iter().enumerate() { + Self::resolve_item(item, i, &mut self.functions, library); + } + } + + pub fn resolve_items(resolved: &mut ResolvedItems, library: &Library, items: &ItemMap) { + let mut i = 0; + items.for_all_items(|item| { + Self::resolve_item(item, i, resolved, library); + i += 1; + }); + } + + fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) { + if let Some(alias) = resolved.remove(&i) { + *item = alias; + } + } + + // Functions do not impl Item + pub fn install_functions(&mut self, items: &mut Vec) { + for (i, item) in items.into_iter().enumerate() { + Self::install_item(item, i, &mut self.functions); + } + } + + pub fn install_items(resolved: &mut ResolvedItems, items: &mut ItemMap) { + let mut i = 0; + items.for_all_items_mut(|item| { + Self::install_item(item, i, resolved); + i += 1; + }); + } +} diff --git a/tests/rust/nonnull.rs b/tests/rust/nonnull.rs index 5ad57f6d..4db03171 100644 --- a/tests/rust/nonnull.rs +++ b/tests/rust/nonnull.rs @@ -19,4 +19,4 @@ pub struct Foo { pub type NonNullPtr = Option>; #[no_mangle] -pub extern "C" fn root(arg: NonNull, foo: *mut Foo, d: NonNull>, e: NonNullPtr>) { } +pub extern "C" fn root(arg: NonNull, foo: *mut Foo, d: NonNull>) { } diff --git a/tests/rust/transparent_typedef.rs b/tests/rust/transparent_typedef.rs index 54563188..de937e1f 100644 --- a/tests/rust/transparent_typedef.rs +++ b/tests/rust/transparent_typedef.rs @@ -1,9 +1,14 @@ use std::num::NonZero; use std::ptr::NonNull; +pub struct Opaque>; + +#[no_mangle] +pub extern "C" fn root_opaque(o: Opaque>>>) {} + #[repr(C)] -pub struct Struct { - field: T, +pub struct Struct> { + field: U, } /// cbindgen:transparent-typedef @@ -169,37 +174,37 @@ pub extern "C" fn root2( n: NotTransparent2>>) {} #[repr(C)] -pub struct FullyTransparentMany>>>>> { - ont: Option>>, - otn: Option>>, - ton: Transparent>>, +pub enum FullyTransparentMany>>>>> { + ont(Option>>), + otn(Option>>), + ton(Transparent>>), // One erasable quadruple - totn: Transparent>>>, + totn(Transparent>>>), - f: extern "C" fn( + f(extern "C" fn( ont: Option>>, otn: Option>>, ton: Transparent>>, - ) -> Transparent>>>, + ) -> Transparent>>>), - onti: Option>>, - otni: Option>>, - toni: Transparent>>, + onti(Option>>), + otni(Option>>), + toni(Transparent>>), // One erasable quadruple - totni: Transparent>>>, + totni(Transparent>>>), - fi: extern "C" fn( + fi(extern "C" fn( onti: Option>>, otni: Option>>, toni: Transparent>>, - ) -> Transparent>>>, + ) -> Transparent>>>), } #[repr(C)] -pub struct PartlyTransparentMany<'a, E = Transparent>>> { +pub union PartlyTransparentMany<'a, E = Transparent>>> { // A few triples tao: &'a Transparent>>, toa: &'a Transparent>>, From 62d45458de261de04dc1965bfe93cff7554bb941 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Tue, 5 Nov 2024 15:56:06 -0800 Subject: [PATCH 06/13] dedup generic param and field resolution --- src/bindgen/ir/enumeration.rs | 46 +++------------------- src/bindgen/ir/function.rs | 23 ----------- src/bindgen/ir/opaque.rs | 26 +------------ src/bindgen/ir/structure.rs | 73 +++-------------------------------- src/bindgen/ir/typedef.rs | 20 +--------- src/bindgen/ir/union.rs | 37 +++--------------- src/bindgen/library.rs | 2 + src/bindgen/transparent.rs | 46 +++++++++++++++++++++- 8 files changed, 69 insertions(+), 204 deletions(-) diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 3e2f58dd..142f000a 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -10,7 +10,7 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, ConditionWrite, GenericParam, DeprecatedNoteKind, Documentation, Field, + AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr, ReprStyle, Struct, ToCondition, Type, }; @@ -648,58 +648,24 @@ impl Item for Enum { impl ResolveTransparentTypes for Enum { fn resolve_transparent_types(&self, library: &Library) -> Option { - // Resolve any defaults in the generic params let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); + let new_params = Self::resolve_generic_params(library, params); let params = new_params.as_ref().unwrap_or(params); - let mut skip_inline_tag_field = Self::inline_tag_field(&self.repr); + let skip_inline_tag_field = Self::inline_tag_field(&self.repr); let variants: Vec<_> = self.variants.iter().map(|v| match v.body { VariantBody::Body { ref name, ref body, inline, inline_casts } => { - let fields: Vec<_> = body.fields.iter().map(|f| { - // Ignore the inline Tag field, if any (it's always first) - if skip_inline_tag_field { - skip_inline_tag_field = false; - None - } else { - Some(Field { - ty: f.ty.transparent_alias(library, params)?, - ..f.clone() - }) - } - }).collect(); - - fields.iter().any(Option::is_some).then(|| { - EnumVariant { + Some(EnumVariant { body: VariantBody::Body { name: name.clone(), body: Struct { - fields: fields.into_iter().zip(&body.fields).map(|(new_field, field)| { - new_field.unwrap_or_else(|| field.clone()) - }).collect(), + fields: Self::resolve_fields(library, &body.fields, params, skip_inline_tag_field)?, ..body.clone() }, inline, inline_casts, }, ..v.clone() - } - }) + }) } VariantBody::Empty(..) => None, }).collect(); diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index d9b59e23..6638c99d 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -144,29 +144,6 @@ impl Function { } } - pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { - // TODO: Dedup with `Type::FuncPtr` case in `Type::transparent_alias` - let empty = GenericParams::empty(); - let new_ret = self.ret.transparent_alias(library, empty); - let new_args: Vec<_> = self.args.iter().map(|arg| arg.ty.transparent_alias(library, empty)).collect(); - (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { - Function { - ret: new_ret.unwrap_or_else(|| self.ret.clone()), - args: new_args - .into_iter() - .zip(&self.args) - .map(|(ty, arg)| { - FunctionArgument { - ty: ty.unwrap_or_else(|| arg.ty.clone()), - ..arg.clone() - } - }) - .collect(), - ..self.clone() - } - }) - } - pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { self.ret.resolve_declaration_types(resolver); for arg in &mut self.args { diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index c5ed1dc8..ff0c55b4 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -2,13 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::borrow::Cow; - use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, Path, + AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, Type, }; use crate::bindgen::library::Library; @@ -185,28 +183,8 @@ impl Item for OpaqueItem { impl ResolveTransparentTypes for OpaqueItem { fn resolve_transparent_types(&self, library: &Library) -> Option { - // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - - if new_params.iter().all(Option::is_none) { - return None; - } - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); Some(OpaqueItem { - generic_params: GenericParams(params.collect()), + generic_params: Self::resolve_generic_params(library, &self.generic_params)?, ..self.clone() }) } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index f86d1548..f82a8379 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -10,7 +10,7 @@ use crate::bindgen::config::{Config, Language, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Constant, GenericParam, Documentation, Field, GenericArgument, GenericParams, Item, + AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; @@ -192,44 +192,6 @@ impl Struct { } } - pub fn resolve_transparent_aliases(&self, library: &Library) -> Option { - // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); - let params = new_params.as_ref().unwrap_or(params); - let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library, params)).collect(); - if new_params.is_none() && types.iter().all(Option::is_none) { - return None; - } - let fields = types.into_iter().zip(&self.fields).map(|(ty, field)| { - Field { - ty: ty.unwrap_or_else(|| field.ty.clone()), - ..field.clone() - } - }).collect(); - Some(Struct { - generic_params: new_params.unwrap_or(self.generic_params.clone()), - fields, - ..self.clone() - }) - } - pub fn specialize( &self, generic_values: &[GenericArgument], @@ -452,38 +414,15 @@ impl ResolveTransparentTypes for Struct { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); + let new_params = Self::resolve_generic_params(library, params); let params = new_params.as_ref().unwrap_or(params); - let types: Vec<_> = self.fields.iter().map(|f| f.ty.transparent_alias(library, params)).collect(); - if new_params.is_none() && types.iter().all(Option::is_none) { + let new_fields = Self::resolve_fields(library, &self.fields, params, false); + if new_params.is_none() && new_fields.is_none() { return None; } - let fields = types.into_iter().zip(&self.fields).map(|(ty, field)| { - warn!("Type of field {:?} changed from {ty:#?}\nto {:#?}", field.name, field.ty); - Field { - ty: ty.unwrap_or_else(|| field.ty.clone()), - ..field.clone() - } - }).collect(); Some(Struct { - generic_params: new_params.unwrap_or(self.generic_params.clone()), - fields, + generic_params: new_params.unwrap_or_else(|| self.generic_params.clone()), + fields: new_fields.unwrap_or_else(|| self.fields.clone()), ..self.clone() }) } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 4d904f24..d121b5cf 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -9,7 +9,7 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Struct, Type, }; use crate::bindgen::library::Library; @@ -213,23 +213,7 @@ impl ResolveTransparentTypes for Typedef { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); + let new_params = Self::resolve_generic_params(library, params); let params = new_params.map_or_else(|| Cow::Borrowed(params), |new_params| Cow::Owned(new_params)); let aliased = self.aliased.transparent_alias(library, ¶ms)?; Some(Typedef { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 9f95f1c6..e0ffd8da 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -8,7 +8,7 @@ use crate::bindgen::config::{Config, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, GenericParam, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, }; use crate::bindgen::library::Library; @@ -267,40 +267,15 @@ impl ResolveTransparentTypes for Union { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params let params = &self.generic_params; - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - } - }).collect(); - let new_params = new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }); + let new_params = Self::resolve_generic_params(library, params); let params = new_params.as_ref().unwrap_or(params); - let types: Vec<_> = self.fields.iter().map(|f| { - Some(Field { - ty: f.ty.transparent_alias(library, params)?, - ..f.clone() - }) - }).collect(); - if new_params.is_none() && types.iter().all(Option::is_none) { + let new_fields = Self::resolve_fields(library, &self.fields, params, false); + if new_params.is_none() && new_fields.is_none() { return None; } - let fields = types.into_iter().zip(&self.fields).map(|(new_field, field)| { - warn!("Type of field {:?} changed from {:#?}\nto {:#?}", field.name, field.ty, new_field); - new_field.unwrap_or_else(|| field.clone()) - }).collect(); Some(Union { - generic_params: new_params.unwrap_or(self.generic_params.clone()), - fields, + generic_params: new_params.unwrap_or_else(|| self.generic_params.clone()), + fields: new_fields.unwrap_or_else(|| self.fields.clone()), ..self.clone() }) } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index cdc8bdab..31b07ab9 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -62,6 +62,8 @@ impl Library { } pub fn generate(mut self) -> Result { + //self.transfer_annotations(); + //self.simplify_standard_types(); self.resolve_transparent_types(); match self.config.function.sort_by.unwrap_or(self.config.sort_by) { diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs index 131b4e15..62b40294 100644 --- a/src/bindgen/transparent.rs +++ b/src/bindgen/transparent.rs @@ -1,10 +1,54 @@ use std::collections::HashMap; -use crate::bindgen::ir::{Constant, Static, Enum, Struct, Union, OpaqueItem, Typedef, Function, Item, ItemMap}; +use crate::bindgen::ir::{Constant, Static, Enum, Struct, Union, OpaqueItem, Typedef, Function, Item, ItemMap, GenericParams, GenericArgument, GenericParam, Field}; use crate::bindgen::library::Library; pub trait ResolveTransparentTypes: Sized { fn resolve_transparent_types(&self, library: &Library) -> Option; + + fn resolve_fields(library: &Library, fields: &[Field], params: &GenericParams, mut skip_first: bool) -> Option> { + let new_fields: Vec<_> = fields.iter().map(|f| { + // Ignore the inline Tag field, if any (it's always first) + if skip_first { + skip_first = false; + None + } else { + Some(Field { + ty: f.ty.transparent_alias(library, params)?, + ..f.clone() + }) + } + }).collect(); + + if new_fields.iter().all(Option::is_none) { + return None; + } + Some(new_fields.into_iter().zip(fields).map(|(new_field, field)| { + new_field.unwrap_or_else(|| field.clone()) + }).collect()) + } + + fn resolve_generic_params(library: &Library, params: &GenericParams) -> Option { + // Resolve defaults in the generic params + let new_params: Vec<_> = params.iter().map(|param| { + match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + } + }).collect(); + + new_params.iter().any(Option::is_some).then(|| { + let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { + new_param.unwrap_or_else(|| param.clone()) + }); + GenericParams(params.collect()) + }) + } } pub type ResolvedItems = HashMap; From 8e429cbcb80744783a5b2600d7a7adb4b909d103 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 6 Nov 2024 14:45:09 -0800 Subject: [PATCH 07/13] Prefer to use Cow instead of Option --- src/bindgen/ir/enumeration.rs | 45 +++++++++-------- src/bindgen/ir/function.rs | 33 ++++++------- src/bindgen/ir/opaque.rs | 13 +++-- src/bindgen/ir/structure.rs | 17 +++---- src/bindgen/ir/ty.rs | 52 ++++++++++---------- src/bindgen/ir/typedef.rs | 13 ++--- src/bindgen/ir/union.rs | 17 +++---- src/bindgen/transparent.rs | 91 ++++++++++++++++++++++++++--------- 8 files changed, 157 insertions(+), 124 deletions(-) diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 142f000a..635e2dab 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::borrow::Cow; use std::io::Write; use syn::ext::IdentExt; @@ -20,7 +21,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; -use crate::bindgen::transparent::ResolveTransparentTypes; +use crate::bindgen::transparent::{CowIsOwned, IterCow, ResolveTransparentTypes}; use crate::bindgen::writer::{ListType, SourceWriter}; #[allow(clippy::large_enum_variant)] @@ -648,36 +649,34 @@ impl Item for Enum { impl ResolveTransparentTypes for Enum { fn resolve_transparent_types(&self, library: &Library) -> Option { - let params = &self.generic_params; - let new_params = Self::resolve_generic_params(library, params); - let params = new_params.as_ref().unwrap_or(params); + // If the enum uses inline tag fields, every variant struct has one. Skip resolving them. + let params = Self::resolve_generic_params(library, &self.generic_params); let skip_inline_tag_field = Self::inline_tag_field(&self.repr); - let variants: Vec<_> = self.variants.iter().map(|v| match v.body { + let variants: Vec<_> = self.variants.iter().cow_map(|v| match v.body { VariantBody::Body { ref name, ref body, inline, inline_casts } => { + let fields = Self::resolve_fields(library, &body.fields, ¶ms, skip_inline_tag_field); + let Cow::Owned(fields) = fields else { + return None; + }; Some(EnumVariant { - body: VariantBody::Body { - name: name.clone(), - body: Struct { - fields: Self::resolve_fields(library, &body.fields, params, skip_inline_tag_field)?, - ..body.clone() - }, - inline, - inline_casts, + body: VariantBody::Body { + name: name.clone(), + body: Struct { + fields, + ..body.clone() }, - ..v.clone() - }) + inline, + inline_casts, + }, + ..v.clone() + }) } VariantBody::Empty(..) => None, }).collect(); - if new_params.is_none() && variants.iter().all(Option::is_none) { - return None; - } - Some(Enum { - generic_params: new_params.unwrap_or(self.generic_params.clone()), - variants: variants.into_iter().zip(&self.variants).map(|(new_variant, variant)| { - new_variant.unwrap_or_else(|| variant.clone()) - }).collect(), + (params.cow_is_owned() || variants.iter().any_owned()).then(|| Enum { + generic_params: params.into_owned(), + variants: variants.into_iter().map(Cow::into_owned).collect(), ..self.clone() }) } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 6638c99d..a8917692 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::borrow::Cow; use std::collections::HashMap; use syn::ext::IdentExt; @@ -14,7 +15,7 @@ use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; -use crate::bindgen::transparent::ResolveTransparentTypes; +use crate::bindgen::transparent::{CowIsOwned, IterCow, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -222,25 +223,19 @@ impl Function { impl ResolveTransparentTypes for Function { fn resolve_transparent_types(&self, library: &Library) -> Option { - // TODO: Dedup with `Type::FuncPtr` case in `Type::transparent_alias` let empty = GenericParams::empty(); - let new_ret = self.ret.transparent_alias(library, empty); - let new_args: Vec<_> = self.args.iter().map(|arg| arg.ty.transparent_alias(library, empty)).collect(); - (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { - Function { - ret: new_ret.unwrap_or_else(|| self.ret.clone()), - args: new_args - .into_iter() - .zip(&self.args) - .map(|(ty, arg)| { - FunctionArgument { - ty: ty.unwrap_or_else(|| arg.ty.clone()), - ..arg.clone() - } - }) - .collect(), - ..self.clone() - } + let ret = self.ret.transparent_alias_cow(library, empty); + let new_args: Vec<_> = self.args.iter().cow_map(|arg| { + Some(FunctionArgument { + ty: arg.ty.transparent_alias(library, empty)?, + ..arg.clone() + }) + }).collect(); + + (ret.cow_is_owned() || new_args.iter().any_owned()).then(|| Function { + ret: ret.into_owned(), + args: new_args.into_iter().map(Cow::into_owned).collect(), + ..self.clone() }) } } diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index ff0c55b4..6a7b387b 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::borrow::Cow; + use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; @@ -183,9 +185,12 @@ impl Item for OpaqueItem { impl ResolveTransparentTypes for OpaqueItem { fn resolve_transparent_types(&self, library: &Library) -> Option { - Some(OpaqueItem { - generic_params: Self::resolve_generic_params(library, &self.generic_params)?, - ..self.clone() - }) + match Self::resolve_generic_params(library, &self.generic_params) { + Cow::Owned(generic_params) => Some(OpaqueItem { + generic_params, + ..self.clone() + }), + _ => None + } } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index f82a8379..03410776 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -18,7 +18,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; -use crate::bindgen::transparent::ResolveTransparentTypes; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::SourceWriter; @@ -413,16 +413,11 @@ impl Item for Struct { impl ResolveTransparentTypes for Struct { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params = Self::resolve_generic_params(library, params); - let params = new_params.as_ref().unwrap_or(params); - let new_fields = Self::resolve_fields(library, &self.fields, params, false); - if new_params.is_none() && new_fields.is_none() { - return None; - } - Some(Struct { - generic_params: new_params.unwrap_or_else(|| self.generic_params.clone()), - fields: new_fields.unwrap_or_else(|| self.fields.clone()), + let params = Self::resolve_generic_params(library, &self.generic_params); + let fields = Self::resolve_fields(library, &self.fields, ¶ms, false); + (params.cow_is_owned() || fields.cow_is_owned()).then(|| Struct { + generic_params: params.into_owned(), + fields: fields.into_owned(), ..self.clone() }) } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 68029671..558720ef 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::borrow::Cow; use syn::ext::IdentExt; use crate::bindgen::config::{Config}; @@ -10,6 +11,7 @@ use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, ItemContainer, Path}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent::{CowIsOwned, IterCow}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -670,6 +672,11 @@ impl Type { .or(Some(erased_type)) } + /// Convenience wrapper for callers who prefer `Cow` instead of `Option` + pub fn transparent_alias_cow<'a>(&'a self, library: &Library, params: &GenericParams) -> Cow<'a, Type> { + self.transparent_alias(library, params).map_or_else(|| Cow::Borrowed(self), Cow::Owned) + } + /// If this type is transparent, recursively replace it with whatever type it aliases. pub fn transparent_alias(&self, library: &Library, params: &GenericParams) -> Option { /* @@ -699,9 +706,9 @@ impl Type { pub fn transparent_alias_impl(&self, library: &Library, params: &GenericParams) -> Option { warn!("Attempt to erase {self:#?}"); */ - match self { + match *self { Type::Ptr { - ty, + ref ty, is_const, is_nullable, is_ref, @@ -710,12 +717,12 @@ impl Type { //warn!("Type::Ptr inner {ty:#?}\nerased as {new_ty:#?}"); Some(Type::Ptr { ty: Box::new(new_ty), - is_const: *is_const, - is_nullable: *is_nullable, - is_ref: *is_ref, + is_const, + is_nullable, + is_ref, }) } - Type::Path(generic_path) => { + Type::Path(ref generic_path) => { let path = generic_path.path(); if params.0.iter().any(|p| p.name() == path) { return None; @@ -748,32 +755,27 @@ impl Type { } } Type::Primitive(_) => None, - Type::Array(ty, expr) => Some(Type::Array( + Type::Array(ref ty, ref expr) => Some(Type::Array( Box::new(ty.transparent_alias(library, params)?), expr.clone(), )), Type::FuncPtr { - ret, - args, + ref ret, + ref args, is_nullable, never_return, } => { - let new_ret = ret.transparent_alias(library, params); - let new_args: Vec<_> = args.iter().map(|(_, ty)| ty.transparent_alias(library, params)).collect(); - (new_ret.is_some() || new_args.iter().any(|arg| arg.is_some())).then(|| { - Type::FuncPtr { - ret: Box::new(new_ret.unwrap_or_else(|| ret.as_ref().clone())), - args: new_args - .into_iter() - .zip(args) - .map(|(new_arg, (name, arg))| { - let new_arg = new_arg.unwrap_or_else(|| arg.clone()); - (name.clone(), new_arg) - }) - .collect(), - is_nullable: *is_nullable, - never_return: *never_return, - } + let ret = ret.transparent_alias_cow(library, params); + let new_args: Vec<_> = args.iter().cow_map(|arg| { + let ty = arg.1.transparent_alias(library, params)?; + Some((arg.0.clone(), ty)) + }).collect(); + + (ret.cow_is_owned() || new_args.iter().any_owned()).then(|| Type::FuncPtr { + ret: Box::new(ret.into_owned()), + args: new_args.into_iter().map(Cow::into_owned).collect(), + is_nullable, + never_return, }) } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index d121b5cf..6a729249 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -2,7 +2,6 @@ * 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; @@ -15,7 +14,7 @@ use crate::bindgen::ir::{ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; -use crate::bindgen::transparent::ResolveTransparentTypes; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; /// A type alias that is represented as a C typedef #[derive(Debug, Clone)] @@ -212,12 +211,10 @@ impl Item for Typedef { impl ResolveTransparentTypes for Typedef { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params = Self::resolve_generic_params(library, params); - let params = new_params.map_or_else(|| Cow::Borrowed(params), |new_params| Cow::Owned(new_params)); - let aliased = self.aliased.transparent_alias(library, ¶ms)?; - Some(Typedef { - aliased, + let params = Self::resolve_generic_params(library, &self.generic_params); + let aliased = self.aliased.transparent_alias_cow(library, ¶ms); + (params.cow_is_owned() || aliased.cow_is_owned()).then(|| Typedef { + aliased: aliased.into_owned(), generic_params: params.into_owned(), ..self.clone() }) diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index e0ffd8da..ab07cfaa 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -15,7 +15,7 @@ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; -use crate::bindgen::transparent::ResolveTransparentTypes; +use crate::bindgen::transparent::{CowIsOwned, ResolveTransparentTypes}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone)] @@ -266,16 +266,11 @@ impl Item for Union { impl ResolveTransparentTypes for Union { fn resolve_transparent_types(&self, library: &Library) -> Option { // Resolve any defaults in the generic params - let params = &self.generic_params; - let new_params = Self::resolve_generic_params(library, params); - let params = new_params.as_ref().unwrap_or(params); - let new_fields = Self::resolve_fields(library, &self.fields, params, false); - if new_params.is_none() && new_fields.is_none() { - return None; - } - Some(Union { - generic_params: new_params.unwrap_or_else(|| self.generic_params.clone()), - fields: new_fields.unwrap_or_else(|| self.fields.clone()), + let params = Self::resolve_generic_params(library, &self.generic_params); + let fields = Self::resolve_fields(library, &self.fields, ¶ms, false); + (params.cow_is_owned() || fields.cow_is_owned()).then(|| Union { + generic_params: params.into_owned(), + fields: fields.into_owned(), ..self.clone() }) } diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs index 62b40294..09bcaf1d 100644 --- a/src/bindgen/transparent.rs +++ b/src/bindgen/transparent.rs @@ -1,13 +1,62 @@ +use std::borrow::Cow; use std::collections::HashMap; use crate::bindgen::ir::{Constant, Static, Enum, Struct, Union, OpaqueItem, Typedef, Function, Item, ItemMap, GenericParams, GenericArgument, GenericParam, Field}; use crate::bindgen::library::Library; +/// Helper trait that makes it easier to work with `Cow` in iterators +pub trait IterCow: Iterator { + /// Maps from `&T` to `Cow<'a, T>` using the provided closure. If the closure returns `Some` + /// result, it is returned as `Cow::Owned`; otherwise, return the item as `Cow::Borrowed`. + fn cow_map<'a, F, T>(self, f: F) -> impl Iterator> + where + F: FnMut(&T) -> Option, + T: Clone + 'a, + Self: Iterator; + + /// True if any item is `Cow::Owned` + fn any_owned<'i, 'a: 'i, T>(self) -> bool + where + T: Clone + 'a, + Self: Iterator>; +} + +// Blanket implementation for all iterators +impl IterCow for I { + fn cow_map<'a, F, T>(self, mut f: F) -> impl Iterator> + where + F: FnMut(&T) -> Option, + T: Clone + 'a, + Self: Iterator, + { + self.map(move |item| f(item).map(Cow::Owned).unwrap_or(Cow::Borrowed(item))) + } + + fn any_owned<'i, 'a: 'i, T>(mut self) -> bool + where + T: Clone + 'a, + Self: Iterator>, + { + self.any(|item| matches!(item, Cow::Owned(_))) + } + +} + +/// Extension trait that compenates for `Cow::is_owned` being unstable +pub trait CowIsOwned { + fn cow_is_owned(&self) -> bool; +} +impl CowIsOwned for Cow<'_, T> { + fn cow_is_owned(&self) -> bool { + matches!(self, Cow::Owned(_)) + } +} + pub trait ResolveTransparentTypes: Sized { fn resolve_transparent_types(&self, library: &Library) -> Option; - fn resolve_fields(library: &Library, fields: &[Field], params: &GenericParams, mut skip_first: bool) -> Option> { - let new_fields: Vec<_> = fields.iter().map(|f| { + fn resolve_fields<'a>(library: &Library, fields: &'a Vec, params: &GenericParams, mut skip_first: bool) -> Cow<'a, Vec> { + let new_fields: Vec<_> = fields.iter().cow_map(|f| { // Ignore the inline Tag field, if any (it's always first) if skip_first { skip_first = false; @@ -20,34 +69,30 @@ pub trait ResolveTransparentTypes: Sized { } }).collect(); - if new_fields.iter().all(Option::is_none) { - return None; + if new_fields.iter().any_owned() { + Cow::Owned(new_fields.into_iter().map(Cow::into_owned).collect()) + } else { + Cow::Borrowed(fields) } - Some(new_fields.into_iter().zip(fields).map(|(new_field, field)| { - new_field.unwrap_or_else(|| field.clone()) - }).collect()) } - fn resolve_generic_params(library: &Library, params: &GenericParams) -> Option { + fn resolve_generic_params<'a>(library: &Library, params: &'a GenericParams) -> Cow<'a, GenericParams> { // Resolve defaults in the generic params - let new_params: Vec<_> = params.iter().map(|param| { - match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, + let new_params: Vec<_> = params.iter().cow_map(|param| match param.default()? { + GenericArgument::Type(ty) => { + // NOTE: Param defaults can reference other params + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) } + _ => None, }).collect(); - new_params.iter().any(Option::is_some).then(|| { - let params = new_params.into_iter().zip(¶ms.0).map(|(new_param, param)| { - new_param.unwrap_or_else(|| param.clone()) - }); - GenericParams(params.collect()) - }) + if new_params.iter().any_owned() { + Cow::Owned(GenericParams(new_params.into_iter().map(Cow::into_owned).collect())) + } else { + Cow::Borrowed(params) + } } } From 1f826fa03cafc6a7e4d593b1f2904bb40cabcc14 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 6 Nov 2024 15:29:10 -0800 Subject: [PATCH 08/13] remove unnecessary trait impl --- src/bindgen/ir/constant.rs | 5 +---- src/bindgen/ir/enumeration.rs | 4 ---- src/bindgen/ir/global.rs | 6 +----- src/bindgen/ir/item.rs | 4 +++- src/bindgen/ir/structure.rs | 7 +++---- src/bindgen/ir/union.rs | 6 +----- 6 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 86caf427..1cecfcd0 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -13,7 +13,7 @@ use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, GenericArgument, GenericParams, Item, + AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path, Struct, ToCondition, Type, }; use crate::bindgen::language_backend::LanguageBackend; @@ -604,9 +604,6 @@ impl Item for Constant { fn generic_params(&self) -> &GenericParams { GenericParams::empty() } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { - None - } } impl ResolveTransparentTypes for Constant { diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 635e2dab..e5fa6e4e 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -503,10 +503,6 @@ impl Item for Enum { &self.generic_params } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { - None - } - fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 68b4df4c..49097650 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -6,7 +6,7 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, GenericArgument, GenericParams, Item, ItemContainer, Path, + AnnotationSet, Cfg, Documentation, GenericParams, Item, ItemContainer, Path, Type, }; use crate::bindgen::library::Library; @@ -111,10 +111,6 @@ impl Item for Static { GenericParams::empty() } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { - None - } - 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 e57f4988..aeca3265 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -43,7 +43,9 @@ pub trait Item { !self.generic_params().is_empty() } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option; + fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { + None // not relevant for most types + } fn rename_for_config(&mut self, _config: &Config) {} fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) {} fn instantiate_monomorph( diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 03410776..3d68e2f6 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -313,10 +313,9 @@ impl Item for Struct { } fn transparent_alias(&self, library: &Library, args: &[GenericArgument], params: &GenericParams) -> Option { - let Some(typedef) = self.as_typedef() else { - return None; - }; - typedef.transparent_alias(library, args, params) + self.as_typedef().and_then(|typedef| { + typedef.transparent_alias(library, args, params) + }) } fn rename_for_config(&mut self, config: &Config) { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index ab07cfaa..0edc6e18 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, Type, + Path, Repr, ReprAlign, ReprStyle, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -163,10 +163,6 @@ impl Item for Union { &self.generic_params } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { - None - } - fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); for field in &mut self.fields { From 29321765ae6d7d5d09da825e1d2eac49ba738419 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 6 Nov 2024 20:38:16 -0800 Subject: [PATCH 09/13] remove simplify_standard_types, no longer needed --- src/bindgen/ir/enumeration.rs | 12 -------- src/bindgen/ir/function.rs | 7 ----- src/bindgen/ir/global.rs | 4 --- src/bindgen/ir/structure.rs | 6 ---- src/bindgen/ir/ty.rs | 55 ----------------------------------- src/bindgen/ir/typedef.rs | 4 --- src/bindgen/ir/union.rs | 6 ---- src/bindgen/library.rs | 24 --------------- 8 files changed, 118 deletions(-) diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index e5fa6e4e..db91e9ef 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -250,12 +250,6 @@ impl EnumVariant { } } - fn simplify_standard_types(&mut self, config: &Config) { - if let VariantBody::Body { ref mut body, .. } = self.body { - body.simplify_standard_types(config); - } - } - fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { if let VariantBody::Body { ref body, .. } = self.body { body.add_dependencies(library, out); @@ -1533,10 +1527,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 a8917692..c1ea83cf 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -117,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 { diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index 49097650..b6ae8773 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -64,10 +64,6 @@ impl Static { documentation, } } - - pub fn simplify_standard_types(&mut self, config: &Config) { - self.ty.simplify_standard_types(config); - } } impl Item for Static { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 3d68e2f6..a13ecfc0 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -161,12 +161,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 { let field = self.fields.first()?; diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 558720ef..cd523dd2 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -519,61 +519,6 @@ impl Type { } } - fn simplified_type(&self, config: &Config) -> Option { - let path = match *self { - Type::Path(ref p) => p, - _ => return None, - }; - - if path.generics().is_empty() { - return None; - } - - if path.generics().len() != 1 { - return None; - } - - let unsimplified_generic = match path.generics()[0] { - GenericArgument::Type(ref ty) => ty, - GenericArgument::Const(_) => return None, - }; - - let generic = match unsimplified_generic.simplified_type(config) { - Some(generic) => Cow::Owned(generic), - None => Cow::Borrowed(unsimplified_generic), - }; - match path.name() { - "Option" => generic - .make_nullable() - .or_else(|| generic.make_zeroable(true)), - "NonNull" => Some(Type::Ptr { - ty: Box::new(generic.into_owned()), - is_const: false, - is_nullable: false, - is_ref: false, - }), - "NonZero" => generic.make_zeroable(false), - "Box" if config.language != Language::Cxx => Some(Type::Ptr { - ty: Box::new(generic.into_owned()), - is_const: false, - is_nullable: false, - is_ref: false, - }), - "SyncUnsafeCell" | "UnsafeCell" | "Cell" => Some(generic.into_owned()), - "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => { - Some(generic.into_owned()) - } - _ => None, - } - } - - pub fn simplify_standard_types(&mut self, config: &Config) { - self.visit_types(|ty| ty.simplify_standard_types(config)); - if let Some(ty) = self.simplified_type(config) { - *self = ty; - } - } - pub fn replace_self_with(&mut self, self_ty: &Path) { if let Type::Path(ref mut generic_path) = *self { generic_path.replace_self_with(self_ty); diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 6a729249..152cf42f 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -68,10 +68,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 { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 0edc6e18..9680cf9f 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -95,12 +95,6 @@ impl Union { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - for field in &mut self.fields { - field.ty.simplify_standard_types(config); - } - } - pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic unions can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 31b07ab9..901caf37 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -63,7 +63,6 @@ impl Library { pub fn generate(mut self) -> Result { //self.transfer_annotations(); - //self.simplify_standard_types(); self.resolve_transparent_types(); match self.config.function.sort_by.unwrap_or(self.config.sort_by) { @@ -369,29 +368,6 @@ impl Library { } } - fn simplify_standard_types(&mut self) { - let config = &self.config; - - self.structs.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.enums.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.unions.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.globals.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - self.typedefs.for_all_items_mut(|x| { - x.simplify_standard_types(config); - }); - for x in &mut self.functions { - x.simplify_standard_types(config); - } - } - fn resolve_transparent_types(&mut self) { let mut resolver = TransparentTypeResolver::default(); TransparentTypeResolver::resolve_items(&mut resolver.constants, self, &self.constants); From 50d4a8cdff6ab39b55d82b1ccdb0f62ac01dacde Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 7 Nov 2024 06:54:00 -0800 Subject: [PATCH 10/13] add test expectations, start to cleanup code --- src/bindgen/ir/ty.rs | 53 +--- src/bindgen/ir/typedef.rs | 2 + src/bindgen/library.rs | 44 ++-- src/bindgen/transparent.rs | 91 ++++--- 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 | 229 +++++++++++++++++ .../expectations/transparent_typedef.compat.c | 237 ++++++++++++++++++ tests/expectations/transparent_typedef.cpp | 225 +++++++++++++++++ tests/expectations/transparent_typedef.pyx | 203 +++++++++++++++ tests/expectations/transparent_typedef_both.c | 229 +++++++++++++++++ .../transparent_typedef_both.compat.c | 237 ++++++++++++++++++ tests/expectations/transparent_typedef_tag.c | 229 +++++++++++++++++ .../transparent_typedef_tag.compat.c | 237 ++++++++++++++++++ .../expectations/transparent_typedef_tag.pyx | 203 +++++++++++++++ tests/rust/transparent_typedef.rs | 35 ++- 23 files changed, 2447 insertions(+), 142 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 diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index cd523dd2..f85c430a 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -8,10 +8,10 @@ use syn::ext::IdentExt; use crate::bindgen::config::{Config}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, ItemContainer, Path}; +use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; -use crate::bindgen::transparent::{CowIsOwned, IterCow}; +use crate::bindgen::transparent::{CowIsOwned, IterCow, TransparentTypeResolver}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -572,52 +572,7 @@ impl Type { } } - pub fn transparent_alias_for_path(&self, path: &Path, generics: &[GenericArgument], library: &Library, params: &GenericParams) -> Option { - let items = library.get_items(path); - if items.is_none() { - warn!("Unknown type {path:?}"); - return None; - } - use crate::bindgen::ir::Item as _; - let mut erased_types = items - .into_iter() - .flatten() - .flat_map(|item| match item { - ItemContainer::Typedef(t) => t.transparent_alias(library, generics, params), - ItemContainer::Struct(s) => { - let t = s.as_typedef()?; - t.transparent_alias(library, generics, params) - } - ItemContainer::OpaqueItem(o) => { - // Opaque type `O` is tricky, because only certain combinations of `O` and - // `T` are transparent. Further, `T` itself may be a transparent type that must - // be resolved before we can make an accurate decision. Additionally, even if we - // ultimately decide `O` is not transparent, we still need to update `O` to - // reference a resolved `T`. For example, `Option>>` - // resolves as `i32` and `Option>` resolves as `Option`. - o.transparent_alias(library, generics, params) - } - _ => None, - }) - //.inspect(|item| warn!("FRJ: erased {self:#?}\nas {item:#?}")) - ; - let Some(erased_type) = erased_types.next() else { - return None; - }; - if let Some(other_erased_type) = erased_types.next() { - warn!( - "Found multiple erased types for {:?}: {:?} vs. {:?}", - path, erased_type, other_erased_type - ); - return None; - } - // The type we just resolved may itself be transparent... recurse - erased_type.transparent_alias(library, params) - //.inspect(|x| warn!("Double erase {path:?}\nfrom {erased_type:#?}\nto{x:#?}")) - .or(Some(erased_type)) - } - - /// Convenience wrapper for callers who prefer `Cow` instead of `Option` + /// Convenience wrapper for callers who prefer `Cow` result over `Option`. pub fn transparent_alias_cow<'a>(&'a self, library: &Library, params: &GenericParams) -> Cow<'a, Type> { self.transparent_alias(library, params).map_or_else(|| Cow::Borrowed(self), Cow::Owned) } @@ -688,7 +643,7 @@ impl Type { }).collect() }); let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); - let new_ty = self.transparent_alias_for_path(path, generics, library, params); + let new_ty = TransparentTypeResolver::transparent_alias_for_path(path, generics, library, params); if new_ty.is_some() { //warn!("Type::Path {self:#?}\nerased as {new_ty:#?}"); new_ty diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 152cf42f..baae63bc 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::collections::HashMap; + use syn::ext::IdentExt; use crate::bindgen::config::Config; diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 901caf37..666a24bd 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -194,6 +194,7 @@ impl Library { .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); } + #[allow(unused)] fn transfer_annotations(&mut self) { let mut annotations = HashMap::new(); @@ -369,24 +370,31 @@ impl Library { } fn resolve_transparent_types(&mut self) { - let mut resolver = TransparentTypeResolver::default(); - TransparentTypeResolver::resolve_items(&mut resolver.constants, self, &self.constants); - TransparentTypeResolver::resolve_items(&mut resolver.globals, self, &self.globals); - TransparentTypeResolver::resolve_items(&mut resolver.enums, self, &self.enums); - TransparentTypeResolver::resolve_items(&mut resolver.structs, self, &self.structs); - TransparentTypeResolver::resolve_items(&mut resolver.unions, self, &self.unions); - TransparentTypeResolver::resolve_items(&mut resolver.opaque_items, self, &self.opaque_items); - TransparentTypeResolver::resolve_items(&mut resolver.typedefs, self, &self.typedefs); - resolver.resolve_functions(self, &self.functions); - - TransparentTypeResolver::install_items(&mut resolver.constants, &mut self.constants); - TransparentTypeResolver::install_items(&mut resolver.globals, &mut self.globals); - TransparentTypeResolver::install_items(&mut resolver.enums, &mut self.enums); - TransparentTypeResolver::install_items(&mut resolver.structs, &mut self.structs); - TransparentTypeResolver::install_items(&mut resolver.unions, &mut self.unions); - TransparentTypeResolver::install_items(&mut resolver.opaque_items, &mut self.opaque_items); - TransparentTypeResolver::install_items(&mut resolver.typedefs, &mut self.typedefs); - resolver.install_functions(&mut self.functions); + let resolver = TransparentTypeResolver; + + let constants = resolver.resolve_items(self, &self.constants); + resolver.install_items(constants, &mut self.constants); + + let globals = resolver.resolve_items(self, &self.globals); + resolver.install_items(globals, &mut self.globals); + + let enums = resolver.resolve_items(self, &self.enums); + resolver.install_items(enums, &mut self.enums); + + let structs = resolver.resolve_items(self, &self.structs); + resolver.install_items(structs, &mut self.structs); + + let unions = resolver.resolve_items(self, &self.unions); + resolver.install_items(unions, &mut self.unions); + + let opaque_items = resolver.resolve_items(self, &self.opaque_items); + resolver.install_items(opaque_items, &mut self.opaque_items); + + let typedefs = resolver.resolve_items(self, &self.typedefs); + resolver.install_items(typedefs, &mut self.typedefs); + + let functions = resolver.resolve_functions(self, &self.functions); + resolver.install_functions(functions, &mut self.functions); } fn instantiate_monomorphs(&mut self) { diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs index 09bcaf1d..c143f0ff 100644 --- a/src/bindgen/transparent.rs +++ b/src/bindgen/transparent.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::collections::HashMap; -use crate::bindgen::ir::{Constant, Static, Enum, Struct, Union, OpaqueItem, Typedef, Function, Item, ItemMap, GenericParams, GenericArgument, GenericParam, Field}; +use crate::bindgen::ir::{Path, Type, Function, Item, ItemMap, GenericParams, GenericArgument, GenericParam, Field}; use crate::bindgen::library::Library; /// Helper trait that makes it easier to work with `Cow` in iterators @@ -98,59 +98,76 @@ pub trait ResolveTransparentTypes: Sized { pub type ResolvedItems = HashMap; -/// An indirection that allows to generalize the two-stage process of resolving transparent types. -#[derive(Default)] -pub struct TransparentTypeResolver { - pub constants: ResolvedItems, - pub globals: ResolvedItems, - pub enums: ResolvedItems, - pub structs: ResolvedItems, - pub unions: ResolvedItems, - pub opaque_items: ResolvedItems, - pub typedefs: ResolvedItems, - pub functions: ResolvedItems, -} +/// An indirection that allows to generalize the two-stage process of resolving transparent +/// types. We first resolve transparent aliases and store the results in a hashmap, using a borrowed +/// reference to the `Library` to resolve the types. In the second step, we install the resolved +/// types back into the library, which requires a mutable reference. +pub struct TransparentTypeResolver; impl TransparentTypeResolver { - fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) { - if let Some(alias) = item.resolve_transparent_types(library) { - resolved.insert(i, alias); + pub fn transparent_alias_for_path(path: &Path, generics: &[GenericArgument], library: &Library, params: &GenericParams) -> Option { + let Some(items) = library.get_items(path) else { + warn!("Unknown type {path:?}"); + return None; + }; + let mut items = items.into_iter(); + let item = items.next()?; + if let Some(other_item) = items.next() { + warn!("Found multiple resolved types for {path:?}: {item:?} and. {other_item:?}"); + return None; } - } - // Functions do not impl Item - pub fn resolve_functions(&mut self, library: &Library, items: &Vec) { - for (i, item) in items.into_iter().enumerate() { - Self::resolve_item(item, i, &mut self.functions, library); - } + // The type we resolve may itself be transparent, so recurse on it + let resolved_type = item.transparent_alias(library, generics, params)?; + resolved_type.transparent_alias(library, params).or(Some(resolved_type)) } - pub fn resolve_items(resolved: &mut ResolvedItems, library: &Library, items: &ItemMap) { + pub fn resolve_items(&self, library: &Library, items: &ItemMap) -> ResolvedItems + where + T: ResolveTransparentTypes + Item + Clone, + { + let mut resolved = Default::default(); let mut i = 0; items.for_all_items(|item| { - Self::resolve_item(item, i, resolved, library); + Self::resolve_item(item, i, &mut resolved, library); i += 1; }); + resolved } - - fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) { - if let Some(alias) = resolved.remove(&i) { - *item = alias; - } + pub fn install_items(&self, mut resolved: ResolvedItems, items: &mut ItemMap) + where + T: ResolveTransparentTypes + Item + Clone, + { + let mut i = 0; + items.for_all_items_mut(|item| { + Self::install_item(item, i, &mut resolved); + i += 1; + }); } // Functions do not impl Item - pub fn install_functions(&mut self, items: &mut Vec) { + pub fn resolve_functions(&self, library: &Library, items: &Vec) -> ResolvedItems { + let mut functions = Default::default(); + for (i, item) in items.into_iter().enumerate() { + Self::resolve_item(item, i, &mut functions, library); + } + functions + } + pub fn install_functions(&self, mut functions: ResolvedItems, items: &mut Vec) { for (i, item) in items.into_iter().enumerate() { - Self::install_item(item, i, &mut self.functions); + Self::install_item(item, i, &mut functions); } } - pub fn install_items(resolved: &mut ResolvedItems, items: &mut ItemMap) { - let mut i = 0; - items.for_all_items_mut(|item| { - Self::install_item(item, i, resolved); - i += 1; - }); + + fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) { + if let Some(alias) = item.resolve_transparent_types(library) { + resolved.insert(i, alias); + } + } + fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) { + if let Some(alias) = resolved.remove(&i) { + *item = alias; + } } } diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 3354bc29..80569f15 100644 --- a/tests/expectations/transparent.c +++ b/tests/expectations/transparent.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent.compat.c b/tests/expectations/transparent.compat.c index 1ebe9a03..2cf10ed9 100644 --- a/tests/expectations/transparent.compat.c +++ b/tests/expectations/transparent.compat.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index aa6091ca..4459f246 100644 --- a/tests/expectations/transparent.cpp +++ b/tests/expectations/transparent.cpp @@ -8,6 +8,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + using TransparentComplexWrappingStructTuple = DummyStruct; using TransparentPrimitiveWrappingStructTuple = uint32_t; @@ -30,7 +32,21 @@ struct TransparentEmptyStructure { }; -constexpr static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN = 10; +using TransparentPointerWrappingStructure = const uint32_t*; + +using TransparentIntStruct = int32_t; + +using TransparentComplexStruct = DummyStruct; + +using TransparentTransparentStruct = TransparentPrimitiveWrappingStructure; + +using TransparentNonNullStruct = uint32_t*; + +using TransparentOptionNonNullStruct = uint32_t*; + +constexpr static const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN = 10; + +constexpr static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN = 10; extern "C" { @@ -42,6 +58,23 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); } // extern "C" diff --git a/tests/expectations/transparent.pyx b/tests/expectations/transparent.pyx index 839c7742..e300f99a 100644 --- a/tests/expectations/transparent.pyx +++ b/tests/expectations/transparent.pyx @@ -12,6 +12,9 @@ cdef extern from *: ctypedef struct EnumWithAssociatedConstantInImpl: pass + ctypedef struct StructWithAssociatedConstantInImpl: + pass + ctypedef DummyStruct TransparentComplexWrappingStructTuple; ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -31,7 +34,21 @@ cdef extern from *: ctypedef struct TransparentEmptyStructure: pass - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN # = 10 + ctypedef const uint32_t *TransparentPointerWrappingStructure; + + ctypedef int32_t TransparentIntStruct; + + ctypedef DummyStruct TransparentComplexStruct; + + ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + + ctypedef uint32_t *TransparentNonNullStruct; + + ctypedef uint32_t *TransparentOptionNonNullStruct; + + const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -41,4 +58,21 @@ cdef extern from *: TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + + void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_both.c b/tests/expectations/transparent_both.c index df9b8a57..042009d5 100644 --- a/tests/expectations/transparent_both.c +++ b/tests/expectations/transparent_both.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct TransparentEmptyStructure { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_both.compat.c b/tests/expectations/transparent_both.compat.c index 4acd6677..21872104 100644 --- a/tests/expectations/transparent_both.compat.c +++ b/tests/expectations/transparent_both.compat.c @@ -7,6 +7,8 @@ typedef struct DummyStruct DummyStruct; typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; +typedef struct StructWithAssociatedConstantInImpl StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ typedef struct TransparentEmptyStructure { } TransparentEmptyStructure; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent_tag.c b/tests/expectations/transparent_tag.c index 2f6dea68..6589eb6b 100644 --- a/tests/expectations/transparent_tag.c +++ b/tests/expectations/transparent_tag.c @@ -7,6 +7,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ struct TransparentEmptyStructure { }; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -37,4 +53,21 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_tag.compat.c b/tests/expectations/transparent_tag.compat.c index 508d6ad6..2eff06ef 100644 --- a/tests/expectations/transparent_tag.compat.c +++ b/tests/expectations/transparent_tag.compat.c @@ -7,6 +7,8 @@ struct DummyStruct; struct EnumWithAssociatedConstantInImpl; +struct StructWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -27,7 +29,21 @@ struct TransparentEmptyStructure { }; -#define EnumWithAssociatedConstantInImpl_TEN 10 +typedef const uint32_t *TransparentPointerWrappingStructure; + +typedef int32_t TransparentIntStruct; + +typedef struct DummyStruct TransparentComplexStruct; + +typedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + +typedef uint32_t *TransparentNonNullStruct; + +typedef uint32_t *TransparentOptionNonNullStruct; + +#define StructWithAssociatedConstantInImpl_STRUCT_TEN 10 + +#define EnumWithAssociatedConstantInImpl_ENUM_TEN 10 #ifdef __cplusplus extern "C" { @@ -41,7 +57,24 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, struct TransparentEmptyStructure h, - struct EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + struct StructWithAssociatedConstantInImpl j, + struct EnumWithAssociatedConstantInImpl k); + +void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + struct DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/transparent_tag.pyx b/tests/expectations/transparent_tag.pyx index 15d66f74..204452d6 100644 --- a/tests/expectations/transparent_tag.pyx +++ b/tests/expectations/transparent_tag.pyx @@ -12,6 +12,9 @@ cdef extern from *: cdef struct EnumWithAssociatedConstantInImpl: pass + cdef struct StructWithAssociatedConstantInImpl: + pass + ctypedef DummyStruct TransparentComplexWrappingStructTuple; ctypedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -31,7 +34,21 @@ cdef extern from *: cdef struct TransparentEmptyStructure: pass - const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN # = 10 + ctypedef const uint32_t *TransparentPointerWrappingStructure; + + ctypedef int32_t TransparentIntStruct; + + ctypedef DummyStruct TransparentComplexStruct; + + ctypedef TransparentPrimitiveWrappingStructure TransparentTransparentStruct; + + ctypedef uint32_t *TransparentNonNullStruct; + + ctypedef uint32_t *TransparentOptionNonNullStruct; + + const TransparentPrimitiveWrappingStructure StructWithAssociatedConstantInImpl_STRUCT_TEN # = 10 + + const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_ENUM_TEN # = 10 void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, @@ -41,4 +58,21 @@ cdef extern from *: TransparentPrimitiveWrapper_i32 f, TransparentPrimitiveWithAssociatedConstants g, TransparentEmptyStructure h, - EnumWithAssociatedConstantInImpl i); + TransparentPointerWrappingStructure i, + StructWithAssociatedConstantInImpl j, + EnumWithAssociatedConstantInImpl k); + + void erased_root(uint32_t *a, + uint32_t *b, + TransparentPrimitiveWrappingStructure c, + uint32_t *d, + TransparentIntStruct e, + int32_t f, + DummyStruct g, + uint32_t *h, + int32_t i, + TransparentIntStruct j, + TransparentComplexStruct k, + TransparentTransparentStruct l, + TransparentNonNullStruct m, + TransparentOptionNonNullStruct n); diff --git a/tests/expectations/transparent_typedef.c b/tests/expectations/transparent_typedef.c new file mode 100644 index 00000000..e0858c11 --- /dev/null +++ b/tests/expectations/transparent_typedef.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct { + const Option_i32 *field; +} Struct_Option_i32; + +typedef Option_i32 Typedef_Option_i32; + +typedef struct { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct { + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct { + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct { + const Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct { + const Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct { + const Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct { + const Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct { + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union { + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +void root_opaque(const Opaque_i32 *o); + +void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + +void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + +void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef.compat.c b/tests/expectations/transparent_typedef.compat.c new file mode 100644 index 00000000..ad2ee828 --- /dev/null +++ b/tests/expectations/transparent_typedef.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct { + const Option_i32 *field; +} Struct_Option_i32; + +typedef Option_i32 Typedef_Option_i32; + +typedef struct { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct { + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct { + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct { + const Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct { + const Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct { + const Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct { + const Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct { + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union { + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const Opaque_i32 *o); + +void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + +void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + +void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef.cpp b/tests/expectations/transparent_typedef.cpp new file mode 100644 index 00000000..a6d98a9f --- /dev/null +++ b/tests/expectations/transparent_typedef.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include + +template +struct Opaque; + +template +struct Option; + +template +struct FullyTransparent1 { + E a; + E *n; + E t; + E (*f)(E a, E *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +template +struct Struct { + const U *field; +}; + +template +using Typedef = U; + +template> +struct NotTransparent1 { + const Option *o; + const Struct *s; + const Typedef *t; + Typedef *(*f)(const Option *o, const Struct *s); + const Option *oi; + const Struct *si; + const Typedef *ti; + Typedef *(*fi)(const Option *oi, const Struct *si); +}; + +template +struct FullyTransparent2 { + E aa; + E *an; + E at; + E *na; + E **nn; + E *nt; + E *on; + E ta; + E *tn; + E tt; + E (*f)(E aa, E *an, E at, E *na, E **nn, E *nt, E *on, E ta, E *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +template> +struct PartlyTransparent2 { + const Option *ao; + const Struct *aS; + const Typedef *at; + Option *const *no; + Struct *const *ns; + Typedef *const *nt; + Typedef **(*f)(const Option *ao, + const Struct *aS, + const Typedef *at, + Option *const *no, + Struct *const *ns); + const Option *aoi; + const Struct *asi; + const Typedef *ati; + Option *const *noi; + Struct *const *nsi; + Typedef *const *nti; + Typedef **(*fi)(const Option *aoi, + const Struct *asi, + const Typedef *ati, + Option *const *noi, + Struct *const *nsi); +}; + +template>> +struct NotTransparent2 { + const Option> *oo; + const Option> *os; + const Struct> *so; + const Struct> *ss; + Struct> *(*f)(const Option> *oo, + const Option> *os, + const Struct> *so); + const Option> *ooi; + const Option> *osi; + const Struct> *soi; + const Struct> *ssi; + Struct> *(*fi)(const Option> *ooi, + const Option> *osi, + const Struct> *soi); +}; + +template +struct FullyTransparentMany { + enum class Tag { + ont, + otn, + ton, + totn, + f, + onti, + otni, + toni, + totni, + fi, + }; + + struct ont_Body { + E *_0; + }; + + struct otn_Body { + E *_0; + }; + + struct ton_Body { + E *_0; + }; + + struct totn_Body { + E *_0; + }; + + struct f_Body { + E *(*_0)(E *ont, E *otn, E *ton); + }; + + struct onti_Body { + int32_t *_0; + }; + + struct otni_Body { + int32_t *_0; + }; + + struct toni_Body { + int32_t *_0; + }; + + struct totni_Body { + int32_t *_0; + }; + + struct fi_Body { + int32_t *(*_0)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + + Tag tag; + union { + ont_Body ont; + otn_Body otn; + ton_Body ton; + totn_Body totn; + f_Body f; + onti_Body onti; + otni_Body otni; + toni_Body toni; + totni_Body totni; + fi_Body fi; + }; +}; + +template> +union PartlyTransparentMany { + const Option *tao; + const Option *toa; + const Option *ota; + const Struct *tas; + const Struct *tsa; + const Struct *sta; + const Option *toat; + const Struct *tsat; + const Option *taoi; + const Option *toai; + const Option *otai; + const Struct *tasi; + const Struct *tsai; + const Struct *stai; + const Option *toati; + const Struct *tsati; +}; + +extern "C" { + +void root_opaque(const Opaque *o); + +void root1(FullyTransparent1 a, NotTransparent1> s); + +void root2(FullyTransparent2 a, + PartlyTransparent2> s, + NotTransparent2>> n); + +void root_many(FullyTransparentMany a, PartlyTransparentMany> b); + +} // extern "C" diff --git a/tests/expectations/transparent_typedef.pyx b/tests/expectations/transparent_typedef.pyx new file mode 100644 index 00000000..e3590f7e --- /dev/null +++ b/tests/expectations/transparent_typedef.pyx @@ -0,0 +1,203 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef struct Opaque_i32: + pass + + ctypedef struct Option_Option_Struct_Option_i32: + pass + + ctypedef struct Option_Option_i32: + pass + + ctypedef struct Option_Struct_Option_i32: + pass + + ctypedef struct Option_Struct_Struct_Option_i32: + pass + + ctypedef struct Option_Struct_i32: + pass + + ctypedef struct Option_i32: + pass + + ctypedef struct FullyTransparent1_i32: + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); + + ctypedef struct Struct_Option_i32: + const Option_i32 *field; + + ctypedef Option_i32 Typedef_Option_i32; + + ctypedef struct Struct_i32: + const int32_t *field; + + ctypedef int32_t Typedef_i32; + + ctypedef struct NotTransparent1_Option_i32: + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); + + ctypedef struct FullyTransparent2_i32: + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); + + ctypedef struct PartlyTransparent2_Option_i32: + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); + + ctypedef struct Struct_Option_Struct_Option_i32: + const Option_Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_Option_i32: + const Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_Struct_Option_i32: + const Struct_Struct_Option_i32 *field; + + ctypedef struct Struct_Struct_i32: + const Struct_i32 *field; + + ctypedef struct NotTransparent2_Struct_Option_i32: + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); + + ctypedef enum FullyTransparentMany_____i32_Tag: + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, + + ctypedef struct FullyTransparentMany_____i32: + FullyTransparentMany_____i32_Tag tag; + int32_t **ont; + int32_t **otn; + int32_t **ton; + int32_t **totn; + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + int32_t *onti; + int32_t *otni; + int32_t *toni; + int32_t *totni; + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + + ctypedef union PartlyTransparentMany_Option_i32: + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; + + void root_opaque(const Opaque_i32 *o); + + void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + + void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + + void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_both.c b/tests/expectations/transparent_typedef_both.c new file mode 100644 index 00000000..d40be94f --- /dev/null +++ b/tests/expectations/transparent_typedef_both.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct Struct_Option_i32 { + const struct Option_i32 *field; +} Struct_Option_i32; + +typedef struct Option_i32 Typedef_Option_i32; + +typedef struct Struct_i32 { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct Struct_Struct_i32 { + const struct Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct FullyTransparentMany_____i32 { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_both.compat.c b/tests/expectations/transparent_typedef_both.compat.c new file mode 100644 index 00000000..6d4705b6 --- /dev/null +++ b/tests/expectations/transparent_typedef_both.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +typedef struct Opaque_i32 Opaque_i32; + +typedef struct Option_Option_Struct_Option_i32 Option_Option_Struct_Option_i32; + +typedef struct Option_Option_i32 Option_Option_i32; + +typedef struct Option_Struct_Option_i32 Option_Struct_Option_i32; + +typedef struct Option_Struct_Struct_Option_i32 Option_Struct_Struct_Option_i32; + +typedef struct Option_Struct_i32 Option_Struct_i32; + +typedef struct Option_i32 Option_i32; + +typedef struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +} FullyTransparent1_i32; + +typedef struct Struct_Option_i32 { + const struct Option_i32 *field; +} Struct_Option_i32; + +typedef struct Option_i32 Typedef_Option_i32; + +typedef struct Struct_i32 { + const int32_t *field; +} Struct_i32; + +typedef int32_t Typedef_i32; + +typedef struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +} NotTransparent1_Option_i32; + +typedef struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +} FullyTransparent2_i32; + +typedef struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +} PartlyTransparent2_Option_i32; + +typedef struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +} Struct_Option_Struct_Option_i32; + +typedef struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +} Struct_Struct_Option_i32; + +typedef struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +} Struct_Struct_Struct_Option_i32; + +typedef struct Struct_Struct_i32 { + const struct Struct_i32 *field; +} Struct_Struct_i32; + +typedef struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +} NotTransparent2_Struct_Option_i32; + +typedef enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +} FullyTransparentMany_____i32_Tag; + +typedef struct FullyTransparentMany_____i32 { + FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +} FullyTransparentMany_____i32; + +typedef union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +} PartlyTransparentMany_Option_i32; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef_tag.c b/tests/expectations/transparent_typedef_tag.c new file mode 100644 index 00000000..d458f456 --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +struct Opaque_i32; + +struct Option_Option_Struct_Option_i32; + +struct Option_Option_i32; + +struct Option_Struct_Option_i32; + +struct Option_Struct_Struct_Option_i32; + +struct Option_Struct_i32; + +struct Option_i32; + +struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +struct Struct_Option_i32 { + const struct Option_i32 *field; +}; + +typedef struct Option_i32 Typedef_Option_i32; + +struct Struct_i32 { + const int32_t *field; +}; + +typedef int32_t Typedef_i32; + +struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +}; + +struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +}; + +struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +}; + +struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +}; + +struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +}; + +struct Struct_Struct_i32 { + const struct Struct_i32 *field; +}; + +struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +}; + +enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +}; + +struct FullyTransparentMany_____i32 { + enum FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +}; + +union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +}; + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); diff --git a/tests/expectations/transparent_typedef_tag.compat.c b/tests/expectations/transparent_typedef_tag.compat.c new file mode 100644 index 00000000..1a13505e --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.compat.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +struct Opaque_i32; + +struct Option_Option_Struct_Option_i32; + +struct Option_Option_i32; + +struct Option_Struct_Option_i32; + +struct Option_Struct_Struct_Option_i32; + +struct Option_Struct_i32; + +struct Option_i32; + +struct FullyTransparent1_i32 { + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); +}; + +struct Struct_Option_i32 { + const struct Option_i32 *field; +}; + +typedef struct Option_i32 Typedef_Option_i32; + +struct Struct_i32 { + const int32_t *field; +}; + +typedef int32_t Typedef_i32; + +struct NotTransparent1_Option_i32 { + const struct Option_Option_i32 *o; + const struct Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const struct Option_Option_i32 *o, const struct Struct_Option_i32 *s); + const struct Option_i32 *oi; + const struct Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const struct Option_i32 *oi, const struct Struct_i32 *si); +}; + +struct FullyTransparent2_i32 { + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); +}; + +struct PartlyTransparent2_Option_i32 { + const struct Option_Option_i32 *ao; + const struct Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + struct Option_Option_i32 *const *no; + struct Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const struct Option_Option_i32 *ao, + const struct Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + struct Option_Option_i32 *const *no, + struct Struct_Option_i32 *const *ns); + const struct Option_i32 *aoi; + const struct Struct_i32 *asi; + const Typedef_i32 *ati; + struct Option_i32 *const *noi; + struct Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const struct Option_i32 *aoi, + const struct Struct_i32 *asi, + const Typedef_i32 *ati, + struct Option_i32 *const *noi, + struct Struct_i32 *const *nsi); +}; + +struct Struct_Option_Struct_Option_i32 { + const struct Option_Struct_Option_i32 *field; +}; + +struct Struct_Struct_Option_i32 { + const struct Struct_Option_i32 *field; +}; + +struct Struct_Struct_Struct_Option_i32 { + const struct Struct_Struct_Option_i32 *field; +}; + +struct Struct_Struct_i32 { + const struct Struct_i32 *field; +}; + +struct NotTransparent2_Struct_Option_i32 { + const struct Option_Option_Struct_Option_i32 *oo; + const struct Option_Struct_Struct_Option_i32 *os; + const struct Struct_Option_Struct_Option_i32 *so; + const struct Struct_Struct_Struct_Option_i32 *ss; + struct Struct_Struct_Struct_Option_i32 *(*f)(const struct Option_Option_Struct_Option_i32 *oo, + const struct Option_Struct_Struct_Option_i32 *os, + const struct Struct_Option_Struct_Option_i32 *so); + const struct Option_Option_i32 *ooi; + const struct Option_Struct_i32 *osi; + const struct Struct_Option_i32 *soi; + const struct Struct_Struct_i32 *ssi; + struct Struct_Struct_i32 *(*fi)(const struct Option_Option_i32 *ooi, + const struct Option_Struct_i32 *osi, + const struct Struct_Option_i32 *soi); +}; + +enum FullyTransparentMany_____i32_Tag { + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, +}; + +struct FullyTransparentMany_____i32 { + enum FullyTransparentMany_____i32_Tag tag; + union { + struct { + int32_t **ont; + }; + struct { + int32_t **otn; + }; + struct { + int32_t **ton; + }; + struct { + int32_t **totn; + }; + struct { + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + }; + struct { + int32_t *onti; + }; + struct { + int32_t *otni; + }; + struct { + int32_t *toni; + }; + struct { + int32_t *totni; + }; + struct { + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + }; + }; +}; + +union PartlyTransparentMany_Option_i32 { + const struct Option_Option_i32 *tao; + const struct Option_Option_i32 *toa; + const struct Option_Option_i32 *ota; + const struct Struct_Option_i32 *tas; + const struct Struct_Option_i32 *tsa; + const struct Struct_Option_i32 *sta; + const struct Option_Option_i32 *toat; + const struct Struct_Option_i32 *tsat; + const struct Option_i32 *taoi; + const struct Option_i32 *toai; + const struct Option_i32 *otai; + const struct Struct_i32 *tasi; + const struct Struct_i32 *tsai; + const struct Struct_i32 *stai; + const struct Option_i32 *toati; + const struct Struct_i32 *tsati; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root_opaque(const struct Opaque_i32 *o); + +void root1(struct FullyTransparent1_i32 a, struct NotTransparent1_Option_i32 s); + +void root2(struct FullyTransparent2_i32 a, + struct PartlyTransparent2_Option_i32 s, + struct NotTransparent2_Struct_Option_i32 n); + +void root_many(struct FullyTransparentMany_____i32 a, union PartlyTransparentMany_Option_i32 b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/transparent_typedef_tag.pyx b/tests/expectations/transparent_typedef_tag.pyx new file mode 100644 index 00000000..87c613ed --- /dev/null +++ b/tests/expectations/transparent_typedef_tag.pyx @@ -0,0 +1,203 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + cdef struct Opaque_i32: + pass + + cdef struct Option_Option_Struct_Option_i32: + pass + + cdef struct Option_Option_i32: + pass + + cdef struct Option_Struct_Option_i32: + pass + + cdef struct Option_Struct_Struct_Option_i32: + pass + + cdef struct Option_Struct_i32: + pass + + cdef struct Option_i32: + pass + + cdef struct FullyTransparent1_i32: + int32_t a; + int32_t *n; + int32_t t; + int32_t (*f)(int32_t a, int32_t *n); + int32_t ai; + int32_t *ni; + int32_t ti; + int32_t (*fi)(int32_t ai, int32_t *ni); + + cdef struct Struct_Option_i32: + const Option_i32 *field; + + ctypedef Option_i32 Typedef_Option_i32; + + cdef struct Struct_i32: + const int32_t *field; + + ctypedef int32_t Typedef_i32; + + cdef struct NotTransparent1_Option_i32: + const Option_Option_i32 *o; + const Struct_Option_i32 *s; + const Typedef_Option_i32 *t; + Typedef_Option_i32 *(*f)(const Option_Option_i32 *o, const Struct_Option_i32 *s); + const Option_i32 *oi; + const Struct_i32 *si; + const Typedef_i32 *ti; + Typedef_i32 *(*fi)(const Option_i32 *oi, const Struct_i32 *si); + + cdef struct FullyTransparent2_i32: + int32_t aa; + int32_t *an; + int32_t at; + int32_t *na; + int32_t **nn; + int32_t *nt; + int32_t *on; + int32_t ta; + int32_t *tn; + int32_t tt; + int32_t (*f)(int32_t aa, + int32_t *an, + int32_t at, + int32_t *na, + int32_t **nn, + int32_t *nt, + int32_t *on, + int32_t ta, + int32_t *tn); + int32_t aai; + int32_t *ani; + int32_t ati; + int32_t *nai; + int32_t **nni; + int32_t *nti; + int32_t *oni; + int32_t tai; + int32_t *tni; + int32_t tti; + int32_t (*fi)(int32_t aai, + int32_t *ani, + int32_t ati, + int32_t *nai, + int32_t **nni, + int32_t *nti, + int32_t *oni, + int32_t tai, + int32_t *tni); + + cdef struct PartlyTransparent2_Option_i32: + const Option_Option_i32 *ao; + const Struct_Option_i32 *aS; + const Typedef_Option_i32 *at; + Option_Option_i32 *const *no; + Struct_Option_i32 *const *ns; + Typedef_Option_i32 *const *nt; + Typedef_Option_i32 **(*f)(const Option_Option_i32 *ao, + const Struct_Option_i32 *aS, + const Typedef_Option_i32 *at, + Option_Option_i32 *const *no, + Struct_Option_i32 *const *ns); + const Option_i32 *aoi; + const Struct_i32 *asi; + const Typedef_i32 *ati; + Option_i32 *const *noi; + Struct_i32 *const *nsi; + Typedef_i32 *const *nti; + Typedef_i32 **(*fi)(const Option_i32 *aoi, + const Struct_i32 *asi, + const Typedef_i32 *ati, + Option_i32 *const *noi, + Struct_i32 *const *nsi); + + cdef struct Struct_Option_Struct_Option_i32: + const Option_Struct_Option_i32 *field; + + cdef struct Struct_Struct_Option_i32: + const Struct_Option_i32 *field; + + cdef struct Struct_Struct_Struct_Option_i32: + const Struct_Struct_Option_i32 *field; + + cdef struct Struct_Struct_i32: + const Struct_i32 *field; + + cdef struct NotTransparent2_Struct_Option_i32: + const Option_Option_Struct_Option_i32 *oo; + const Option_Struct_Struct_Option_i32 *os; + const Struct_Option_Struct_Option_i32 *so; + const Struct_Struct_Struct_Option_i32 *ss; + Struct_Struct_Struct_Option_i32 *(*f)(const Option_Option_Struct_Option_i32 *oo, + const Option_Struct_Struct_Option_i32 *os, + const Struct_Option_Struct_Option_i32 *so); + const Option_Option_i32 *ooi; + const Option_Struct_i32 *osi; + const Struct_Option_i32 *soi; + const Struct_Struct_i32 *ssi; + Struct_Struct_i32 *(*fi)(const Option_Option_i32 *ooi, + const Option_Struct_i32 *osi, + const Struct_Option_i32 *soi); + + cdef enum FullyTransparentMany_____i32_Tag: + ont_____i32, + otn_____i32, + ton_____i32, + totn_____i32, + f_____i32, + onti_____i32, + otni_____i32, + toni_____i32, + totni_____i32, + fi_____i32, + + cdef struct FullyTransparentMany_____i32: + FullyTransparentMany_____i32_Tag tag; + int32_t **ont; + int32_t **otn; + int32_t **ton; + int32_t **totn; + int32_t **(*f)(int32_t **ont, int32_t **otn, int32_t **ton); + int32_t *onti; + int32_t *otni; + int32_t *toni; + int32_t *totni; + int32_t *(*fi)(int32_t *onti, int32_t *otni, int32_t *toni); + + cdef union PartlyTransparentMany_Option_i32: + const Option_Option_i32 *tao; + const Option_Option_i32 *toa; + const Option_Option_i32 *ota; + const Struct_Option_i32 *tas; + const Struct_Option_i32 *tsa; + const Struct_Option_i32 *sta; + const Option_Option_i32 *toat; + const Struct_Option_i32 *tsat; + const Option_i32 *taoi; + const Option_i32 *toai; + const Option_i32 *otai; + const Struct_i32 *tasi; + const Struct_i32 *tsai; + const Struct_i32 *stai; + const Option_i32 *toati; + const Struct_i32 *tsati; + + void root_opaque(const Opaque_i32 *o); + + void root1(FullyTransparent1_i32 a, NotTransparent1_Option_i32 s); + + void root2(FullyTransparent2_i32 a, + PartlyTransparent2_Option_i32 s, + NotTransparent2_Struct_Option_i32 n); + + void root_many(FullyTransparentMany_____i32 a, PartlyTransparentMany_Option_i32 b); diff --git a/tests/rust/transparent_typedef.rs b/tests/rust/transparent_typedef.rs index de937e1f..7987aabf 100644 --- a/tests/rust/transparent_typedef.rs +++ b/tests/rust/transparent_typedef.rs @@ -1,19 +1,10 @@ use std::num::NonZero; use std::ptr::NonNull; -pub struct Opaque>; - -#[no_mangle] -pub extern "C" fn root_opaque(o: Opaque>>>) {} - -#[repr(C)] -pub struct Struct> { - field: U, -} /// cbindgen:transparent-typedef #[repr(transparent)] -pub struct Transparent { +pub struct Transparent> { field: T, _phantom: std::marker::PhantomData

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

, +} + #[repr(C)] pub struct FullyTransparent1> { a: Alias, @@ -50,15 +54,6 @@ pub struct NotTransparent1<'a, E = Option> { fi: extern "C" fn(oi: &Option, si: &Struct) -> *mut Typedef, } -#[no_mangle] -pub extern "C" fn test1( - a: Struct, - b: Typedef, - c: &Option, - d: Transparent, - e: Alias, -) {} - #[no_mangle] pub extern "C" fn root1( a: FullyTransparent1>, @@ -174,7 +169,7 @@ pub extern "C" fn root2( n: NotTransparent2>>) {} #[repr(C)] -pub enum FullyTransparentMany>>>>> { +pub enum FullyTransparentMany>>>>> { ont(Option>>), otn(Option>>), ton(Transparent>>), From a5e3cbd1a2dcee4b5705789e161ec6c027cdbe2f Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 7 Nov 2024 10:02:11 -0800 Subject: [PATCH 11/13] Final cleanups --- src/bindgen/ir/constant.rs | 4 +- src/bindgen/ir/enumeration.rs | 50 +++++++----- src/bindgen/ir/function.rs | 22 ++++-- src/bindgen/ir/global.rs | 3 +- src/bindgen/ir/item.rs | 5 +- src/bindgen/ir/opaque.rs | 68 ++++++---------- src/bindgen/ir/structure.rs | 15 ++-- src/bindgen/ir/ty.rs | 112 ++++++++++----------------- src/bindgen/ir/typedef.rs | 26 +++---- src/bindgen/ir/union.rs | 1 - src/bindgen/library.rs | 59 +++++++------- src/bindgen/parser.rs | 7 +- src/bindgen/transparent.rs | 141 +++++++++++++++++++++++----------- 13 files changed, 265 insertions(+), 248 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 1cecfcd0..d75b0068 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, GenericParams, Item, ItemContainer, Path, + Struct, ToCondition, Type, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index db91e9ef..80a29b8c 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -642,27 +642,37 @@ impl ResolveTransparentTypes for Enum { // If the enum uses inline tag fields, every variant struct has one. Skip resolving them. let params = Self::resolve_generic_params(library, &self.generic_params); let skip_inline_tag_field = Self::inline_tag_field(&self.repr); - let variants: Vec<_> = self.variants.iter().cow_map(|v| match v.body { - VariantBody::Body { ref name, ref body, inline, inline_casts } => { - let fields = Self::resolve_fields(library, &body.fields, ¶ms, skip_inline_tag_field); - let Cow::Owned(fields) = fields else { - return None; - }; - Some(EnumVariant { - body: VariantBody::Body { - name: name.clone(), - body: Struct { - fields, - ..body.clone() + let variants: Vec<_> = self + .variants + .iter() + .cow_map(|v| match v.body { + VariantBody::Body { + ref name, + ref body, + inline, + inline_casts, + } => { + let fields = + Self::resolve_fields(library, &body.fields, ¶ms, skip_inline_tag_field); + let Cow::Owned(fields) = fields else { + return None; + }; + Some(EnumVariant { + body: VariantBody::Body { + name: name.clone(), + body: Struct { + fields, + ..body.clone() + }, + inline, + inline_casts, }, - inline, - inline_casts, - }, - ..v.clone() - }) - } - VariantBody::Empty(..) => None, - }).collect(); + ..v.clone() + }) + } + VariantBody::Empty(..) => None, + }) + .collect(); (params.cow_is_owned() || variants.iter().any_owned()).then(|| Enum { generic_params: params.into_owned(), diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index c1ea83cf..327258e3 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -10,7 +10,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, GenericParams, Documentation, GenericPath, Path, Type}; +use crate::bindgen::ir::{ + AnnotationSet, Cfg, Documentation, GenericParams, GenericPath, Path, Type, +}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; @@ -218,16 +220,20 @@ impl ResolveTransparentTypes for Function { fn resolve_transparent_types(&self, library: &Library) -> Option { let empty = GenericParams::empty(); let ret = self.ret.transparent_alias_cow(library, empty); - let new_args: Vec<_> = self.args.iter().cow_map(|arg| { - Some(FunctionArgument { - ty: arg.ty.transparent_alias(library, empty)?, - ..arg.clone() + let args: Vec<_> = self + .args + .iter() + .cow_map(|arg| { + Some(FunctionArgument { + ty: arg.ty.transparent_alias(library, empty)?, + ..arg.clone() + }) }) - }).collect(); + .collect(); - (ret.cow_is_owned() || new_args.iter().any_owned()).then(|| Function { + (ret.cow_is_owned() || args.iter().any_owned()).then(|| Function { ret: ret.into_owned(), - args: new_args.into_iter().map(Cow::into_owned).collect(), + args: args.into_iter().map(Cow::into_owned).collect(), ..self.clone() }) } diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index b6ae8773..75dd35bf 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -6,8 +6,7 @@ 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, GenericParams, Item, ItemContainer, Path, Type, }; use crate::bindgen::library::Library; use crate::bindgen::transparent::ResolveTransparentTypes; diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index aeca3265..6040c01a 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, Type, Typedef, Union, + Path, Static, Struct, Typedef, Union, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -43,9 +43,6 @@ pub trait Item { !self.generic_params().is_empty() } - fn transparent_alias(&self, _library: &Library, _args: &[GenericArgument], _params: &GenericParams) -> Option { - None // not relevant for most types - } fn rename_for_config(&mut self, _config: &Config) {} fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) {} fn instantiate_monomorph( diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 6a7b387b..5356939c 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -59,6 +59,30 @@ impl OpaqueItem { documentation, } } + + pub fn transparent_alias(&self, args: &[GenericArgument]) -> Option { + if !self.is_generic() { + return None; + } + let Some(GenericArgument::Type(ty)) = args.first() else { + return None; + }; + let ty = match self.name() { + // NonNull is always transparent, but needs to transform `T` + "NonNull" => Type::Ptr { + ty: Box::new(ty.clone()), + is_const: false, + is_nullable: false, + is_ref: false, + }, + // NonZero is only transparent if T is zeroable + "NonZero" => ty.make_zeroable(false)?, + // Option is only transparent if T is non-zeroable or non-nullable + "Option" => ty.make_zeroable(true).or_else(|| ty.make_nullable())?, + _ => return None, + }; + Some(ty) + } } impl Item for OpaqueItem { @@ -98,48 +122,6 @@ impl Item for OpaqueItem { &self.generic_params } - fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { - // NOTE: Our caller already resolved the params, no need to resolve them again here. - if !self.is_generic() { - return None; - } - let Some(GenericArgument::Type(ty)) = args.first() else { - return None; - }; - // We have to specialize before resolving, in case the args themselves get resolved - // - // NOTE: Unlike e.g. struct or typedef, specializing opaque types is just a direct - // replacement. Otherwise, specializing `Option>` for `T` would produce - // `Option>>`. See also `OpaqueItem::instantiate_monomorph` below. - let ty = if let Some(GenericArgument::Type(new_ty)) = args.first() { - new_ty - } else { - ty - }; - //let resolved_ty = ty.transparent_alias(library, params); - //let ty = resolved_ty.map_or_else(|| Cow::Borrowed(ty), |resolved| Cow::Owned(resolved)); - let ty = match self.name() { - "NonNull" => { - //warn!("Processing {self:#?}"); - Type::Ptr { - ty: Box::new(ty.clone()), - is_const: false, - is_nullable: false, - is_ref: false, - } - } - "NonZero" => ty.make_zeroable(false)?, - "Option" => { - warn!("Processing {self:#?}\nwith T={ty:#?}"); - ty.make_zeroable(true).or_else(|| ty.make_nullable().inspect(|n| warn!("=> became {n:#?}")))? - } - _ => return None, - }; - Some(ty) - //let mappings = self.generic_params.call(self.path.name(), args); - //Some(ty.specialize(&mappings)).inspect(|x| warn!("specialized {:#?}\nfrom {ty:#?}\nto {x:#?}\nwith mappings {mappings:#?}", args.first())) - } - fn rename_for_config(&mut self, config: &Config) { config.export.rename(&mut self.export_name); } @@ -190,7 +172,7 @@ impl ResolveTransparentTypes for OpaqueItem { generic_params, ..self.clone() }), - _ => None + _ => None, } } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index a13ecfc0..ba193faa 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -164,8 +164,13 @@ impl Struct { /// Attempts to convert this struct to a typedef (only works for transparent structs). pub fn as_typedef(&self) -> Option { let field = self.fields.first()?; - self.is_transparent.then(|| Typedef::new_from_struct_field(self, field)) - //.inspect(|field| warn!("FRJ replaced {self:#?}\nwith {field:#?}")) + self.is_transparent + .then(|| Typedef::new_from_struct_field(self, field)) + } + + pub fn transparent_alias(&self, args: &[GenericArgument]) -> Option { + self.as_typedef() + .and_then(|typedef| typedef.transparent_alias(args)) } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { @@ -306,12 +311,6 @@ impl Item for Struct { &self.generic_params } - fn transparent_alias(&self, library: &Library, args: &[GenericArgument], params: &GenericParams) -> Option { - self.as_typedef().and_then(|typedef| { - typedef.transparent_alias(library, args, params) - }) - } - 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 f85c430a..231fc377 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use syn::ext::IdentExt; -use crate::bindgen::config::{Config}; +use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path}; @@ -573,86 +573,54 @@ impl Type { } /// Convenience wrapper for callers who prefer `Cow` result over `Option`. - pub fn transparent_alias_cow<'a>(&'a self, library: &Library, params: &GenericParams) -> Cow<'a, Type> { - self.transparent_alias(library, params).map_or_else(|| Cow::Borrowed(self), Cow::Owned) + pub fn transparent_alias_cow<'a>( + &'a self, + library: &Library, + params: &GenericParams, + ) -> Cow<'a, Type> { + self.transparent_alias(library, params) + .map_or_else(|| Cow::Borrowed(self), Cow::Owned) } /// If this type is transparent, recursively replace it with whatever type it aliases. pub fn transparent_alias(&self, library: &Library, params: &GenericParams) -> Option { - /* - if let Some(resolved) = self.transparent_alias_impl(library, params) - { - warn!("erased {self:#?}\nas {resolved:#?}"); - Some(resolved) - } else if generic_path.{ - // process the generics first -- they may change even if this type isn't transparent - let generics = generic_path.generics(); - let new_generics: Vec<_> = generics.iter().map(|arg| match arg { - GenericArgument::Type(ty) => { - let new_ty = ty.transparent_alias(library, params)?; - //warn!("GenericArgument::Type {ty:#?}\nerased as {new_ty:#?}"); - Some(GenericArgument::Type(new_ty)) - } - _ => None - }).collect(); - let new_generics = new_generics.iter().any(Option::is_some).then(|| -> Vec<_> { - new_generics.into_iter().zip(generics).map(|(new_arg, arg)| { - new_arg.unwrap_or_else(|| arg.clone()) - }).collect() - }); - let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); - } - } - pub fn transparent_alias_impl(&self, library: &Library, params: &GenericParams) -> Option { - warn!("Attempt to erase {self:#?}"); - */ match *self { Type::Ptr { ref ty, is_const, is_nullable, is_ref, - } => { - let new_ty = ty.transparent_alias(library, params)?; - //warn!("Type::Ptr inner {ty:#?}\nerased as {new_ty:#?}"); - Some(Type::Ptr { - ty: Box::new(new_ty), - is_const, - is_nullable, - is_ref, - }) - } + } => Some(Type::Ptr { + ty: Box::new(ty.transparent_alias(library, params)?), + is_const, + is_nullable, + is_ref, + }), Type::Path(ref generic_path) => { let path = generic_path.path(); if params.0.iter().any(|p| p.name() == path) { - return None; + return None; // Don't try to resolve template parameters! } - // process the generics first -- they may change even if this type isn't transparent + // Resolve the generics first -- they may change even if this type isn't transparent let generics = generic_path.generics(); - let new_generics: Vec<_> = generics.iter().map(|arg| match arg { - GenericArgument::Type(ty) => { - let new_ty = ty.transparent_alias(library, params)?; - //warn!("GenericArgument::Type {ty:#?}\nerased as {new_ty:#?}"); - Some(GenericArgument::Type(new_ty)) - } - _ => None - }).collect(); - let new_generics = new_generics.iter().any(Option::is_some).then(|| -> Vec<_> { - new_generics.into_iter().zip(generics).map(|(new_arg, arg)| { - new_arg.unwrap_or_else(|| arg.clone()) - }).collect() - }); + let new_generics: Vec<_> = generics + .iter() + .cow_map(|arg| match arg { + GenericArgument::Type(ty) => Some(GenericArgument::Type( + ty.transparent_alias(library, params)?, + )), + _ => None, + }) + .collect(); + let new_generics = new_generics + .iter() + .any_owned() + .then(|| new_generics.into_iter().map(Cow::into_owned).collect()); let generics = new_generics.as_ref().map_or(generics, Vec::as_slice); - let new_ty = TransparentTypeResolver::transparent_alias_for_path(path, generics, library, params); - if new_ty.is_some() { - //warn!("Type::Path {self:#?}\nerased as {new_ty:#?}"); - new_ty - } else { - //if let Some(ref new_generics) = new_generics { - // warn!("Type::Path args {path:?} simplified to {new_generics:#?}"); - //} - new_generics.map(|g| Type::Path(GenericPath::new(path.clone(), g))) - } + let ty = TransparentTypeResolver::transparent_alias_for_path( + path, generics, library, params, + ); + ty.or_else(|| Some(Type::Path(GenericPath::new(path.clone(), new_generics?)))) } Type::Primitive(_) => None, Type::Array(ref ty, ref expr) => Some(Type::Array( @@ -666,14 +634,16 @@ impl Type { never_return, } => { let ret = ret.transparent_alias_cow(library, params); - let new_args: Vec<_> = args.iter().cow_map(|arg| { - let ty = arg.1.transparent_alias(library, params)?; - Some((arg.0.clone(), ty)) - }).collect(); + let args: Vec<_> = args + .iter() + .cow_map(|(name, ty)| { + Some((name.clone(), ty.transparent_alias(library, params)?)) + }) + .collect(); - (ret.cow_is_owned() || new_args.iter().any_owned()).then(|| Type::FuncPtr { + (ret.cow_is_owned() || args.iter().any_owned()).then(|| Type::FuncPtr { ret: Box::new(ret.into_owned()), - args: new_args.into_iter().map(Cow::into_owned).collect(), + args: args.into_iter().map(Cow::into_owned).collect(), is_nullable, never_return, }) diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index baae63bc..42cc1d38 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -102,6 +102,19 @@ impl Typedef { } } + pub fn transparent_alias(&self, args: &[GenericArgument]) -> Option { + matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { + // Specialize the aliased type (if needed) and return it. We don't need to resolve + // params, because our caller processes transparent aliases iteratively to fixpoint. + if self.is_generic() { + let mappings = self.generic_params.call(self.path.name(), args); + self.aliased.specialize(&mappings) + } else { + self.aliased.clone() + } + }) + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. @@ -156,19 +169,6 @@ impl Item for Typedef { &self.generic_params } - fn transparent_alias(&self, _library: &Library, args: &[GenericArgument], _params: &GenericParams) -> Option { - matches!(self.annotations.bool(Self::TRANSPARENT_TYPEDEF), Some(true)).then(|| { - // Specialize the aliased type (if needed) and return it. We don't need to resolve - // params, because our caller processes transparent aliases iteratively to fixpoint. - if self.is_generic() { - let mappings = self.generic_params.call(self.path.name(), args); - self.aliased.specialize(&mappings) - } else { - self.aliased.clone() - } - }) - } - 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 9680cf9f..e60c3de5 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -255,7 +255,6 @@ impl Item for Union { impl ResolveTransparentTypes for Union { fn resolve_transparent_types(&self, library: &Library) -> Option { - // Resolve any defaults in the generic params let params = Self::resolve_generic_params(library, &self.generic_params); let fields = Self::resolve_fields(library, &self.fields, ¶ms, false); (params.cow_is_owned() || fields.cow_is_owned()).then(|| Union { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 666a24bd..0346dee3 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -62,8 +62,8 @@ impl Library { } pub fn generate(mut self) -> Result { - //self.transfer_annotations(); self.resolve_transparent_types(); + self.transfer_annotations(); 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)), @@ -194,7 +194,6 @@ impl Library { .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); } - #[allow(unused)] fn transfer_annotations(&mut self) { let mut annotations = HashMap::new(); @@ -320,6 +319,34 @@ impl Library { } } + fn resolve_transparent_types(&mut self) { + let resolver = TransparentTypeResolver; + + let constants = resolver.resolve_items(self, &self.constants); + resolver.install_items(constants, &mut self.constants); + + let globals = resolver.resolve_items(self, &self.globals); + resolver.install_items(globals, &mut self.globals); + + let enums = resolver.resolve_items(self, &self.enums); + resolver.install_items(enums, &mut self.enums); + + let structs = resolver.resolve_items(self, &self.structs); + resolver.install_items(structs, &mut self.structs); + + let unions = resolver.resolve_items(self, &self.unions); + resolver.install_items(unions, &mut self.unions); + + let opaque_items = resolver.resolve_items(self, &self.opaque_items); + resolver.install_items(opaque_items, &mut self.opaque_items); + + let typedefs = resolver.resolve_items(self, &self.typedefs); + resolver.install_items(typedefs, &mut self.typedefs); + + let functions = resolver.resolve_functions(self, &self.functions); + resolver.install_functions(functions, &mut self.functions); + } + fn resolve_declaration_types(&mut self) { if !self.config.style.generate_tag() { return; @@ -369,34 +396,6 @@ impl Library { } } - fn resolve_transparent_types(&mut self) { - let resolver = TransparentTypeResolver; - - let constants = resolver.resolve_items(self, &self.constants); - resolver.install_items(constants, &mut self.constants); - - let globals = resolver.resolve_items(self, &self.globals); - resolver.install_items(globals, &mut self.globals); - - let enums = resolver.resolve_items(self, &self.enums); - resolver.install_items(enums, &mut self.enums); - - let structs = resolver.resolve_items(self, &self.structs); - resolver.install_items(structs, &mut self.structs); - - let unions = resolver.resolve_items(self, &self.unions); - resolver.install_items(unions, &mut self.unions); - - let opaque_items = resolver.resolve_items(self, &self.opaque_items); - resolver.install_items(opaque_items, &mut self.opaque_items); - - let typedefs = resolver.resolve_items(self, &self.typedefs); - resolver.install_items(typedefs, &mut self.typedefs); - - let functions = resolver.resolve_functions(self, &self.functions); - resolver.install_functions(functions, &mut self.functions); - } - fn instantiate_monomorphs(&mut self) { // Collect a list of monomorphs let mut monomorphs = Monomorphs::default(); diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 235a817e..24cc5abb 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -15,8 +15,9 @@ use crate::bindgen::cargo::{Cargo, PackageRef}; use crate::bindgen::config::{Config, Language, ParseConfig}; use crate::bindgen::error::Error; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, Constant, Documentation, Enum, Function, GenericPath, GenericArgument, 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}; @@ -496,7 +497,7 @@ impl Parse { self.add_opaque("MaybeUninit", vec!["T"]); self.add_opaque("Pin", vec!["T"]); } else { - // NOTE: Box acts like NonNull in C + // NOTE: Box acts like NonNull in C, so emit it as a transparent typedef let generics = vec![GenericArgument::Type(tpath.clone())]; let alias = Type::Path(GenericPath::new(Path::new("NonNull"), generics)); self.add_transparent_typedef("Box", alias, vec!["T"]); diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs index c143f0ff..660e41ae 100644 --- a/src/bindgen/transparent.rs +++ b/src/bindgen/transparent.rs @@ -1,12 +1,15 @@ use std::borrow::Cow; use std::collections::HashMap; -use crate::bindgen::ir::{Path, Type, Function, Item, ItemMap, GenericParams, GenericArgument, GenericParam, Field}; +use crate::bindgen::ir::{ + Field, Function, GenericArgument, GenericParam, GenericParams, Item, ItemContainer, ItemMap, + Path, Type, +}; use crate::bindgen::library::Library; /// Helper trait that makes it easier to work with `Cow` in iterators pub trait IterCow: Iterator { - /// Maps from `&T` to `Cow<'a, T>` using the provided closure. If the closure returns `Some` + /// Maps from `&T` to `Cow<'a, T>` using the provided function. If the function returns `Some` /// result, it is returned as `Cow::Owned`; otherwise, return the item as `Cow::Borrowed`. fn cow_map<'a, F, T>(self, f: F) -> impl Iterator> where @@ -29,7 +32,7 @@ impl IterCow for I { T: Clone + 'a, Self: Iterator, { - self.map(move |item| f(item).map(Cow::Owned).unwrap_or(Cow::Borrowed(item))) + self.map(move |item| f(item).map_or_else(|| Cow::Borrowed(item), Cow::Owned)) } fn any_owned<'i, 'a: 'i, T>(mut self) -> bool @@ -39,7 +42,6 @@ impl IterCow for I { { self.any(|item| matches!(item, Cow::Owned(_))) } - } /// Extension trait that compenates for `Cow::is_owned` being unstable @@ -53,21 +55,34 @@ impl CowIsOwned for Cow<'_, T> { } pub trait ResolveTransparentTypes: Sized { + /// Attempts to resolve transparent aliases for all `Type` instances in this item. This includes + /// directly embedded types as well as generic parameter defaults, if any. fn resolve_transparent_types(&self, library: &Library) -> Option; - fn resolve_fields<'a>(library: &Library, fields: &'a Vec, params: &GenericParams, mut skip_first: bool) -> Cow<'a, Vec> { - let new_fields: Vec<_> = fields.iter().cow_map(|f| { - // Ignore the inline Tag field, if any (it's always first) - if skip_first { - skip_first = false; - None - } else { - Some(Field { - ty: f.ty.transparent_alias(library, params)?, - ..f.clone() - }) - } - }).collect(); + /// Attempts to resolve transparent aliases for the types of a slice of fields. A `Cow::Owned` + /// result means at least one field was modified as a result; otherwise, the original fields are + /// returned as a `Cow::Borrowed` result. + fn resolve_fields<'a>( + library: &Library, + fields: &'a Vec, + params: &GenericParams, + mut skip_first: bool, + ) -> Cow<'a, Vec> { + let new_fields: Vec<_> = fields + .iter() + .cow_map(|f| { + // Ignore the inline Tag field, if any (it's always first, when present at all) + if skip_first { + skip_first = false; + None + } else { + Some(Field { + ty: f.ty.transparent_alias(library, params)?, + ..f.clone() + }) + } + }) + .collect(); if new_fields.iter().any_owned() { Cow::Owned(new_fields.into_iter().map(Cow::into_owned).collect()) @@ -76,20 +91,31 @@ pub trait ResolveTransparentTypes: Sized { } } - fn resolve_generic_params<'a>(library: &Library, params: &'a GenericParams) -> Cow<'a, GenericParams> { - // Resolve defaults in the generic params - let new_params: Vec<_> = params.iter().cow_map(|param| match param.default()? { - GenericArgument::Type(ty) => { - // NOTE: Param defaults can reference other params - let new_ty = ty.transparent_alias(library, params)?; - let default = Some(GenericArgument::Type(new_ty)); - Some(GenericParam::new_type_param(param.name().name(), default)) - } - _ => None, - }).collect(); + /// Attempts to resolve transparent aliases for the types of default values in a generic + /// parameter list. A `Cow::Owned` return value means at least one field was modified as a + /// result; otherwise, the original params are returned as a `Cow::Borrowed` value. + fn resolve_generic_params<'a>( + library: &Library, + params: &'a GenericParams, + ) -> Cow<'a, GenericParams> { + let new_params: Vec<_> = params + .iter() + .cow_map(|param| match param.default() { + Some(GenericArgument::Type(ty)) => { + // NOTE: Param defaults can reference other params, so forward the param list to + // the type resolution to allow for proper substitutions to be made. + let new_ty = ty.transparent_alias(library, params)?; + let default = Some(GenericArgument::Type(new_ty)); + Some(GenericParam::new_type_param(param.name().name(), default)) + } + _ => None, + }) + .collect(); if new_params.iter().any_owned() { - Cow::Owned(GenericParams(new_params.into_iter().map(Cow::into_owned).collect())) + Cow::Owned(GenericParams( + new_params.into_iter().map(Cow::into_owned).collect(), + )) } else { Cow::Borrowed(params) } @@ -99,13 +125,20 @@ pub trait ResolveTransparentTypes: Sized { pub type ResolvedItems = HashMap; /// An indirection that allows to generalize the two-stage process of resolving transparent -/// types. We first resolve transparent aliases and store the results in a hashmap, using a borrowed -/// reference to the `Library` to resolve the types. In the second step, we install the resolved -/// types back into the library, which requires a mutable reference. +/// types. We first call a `resolve_XXX` function to resolve transparent aliases and store the +/// results in a hashmap, using a borrowed reference to the `Library` to resolve the types. In the +/// second step, we call an `install_XXX` function to update a mutable reference to the `Library`. pub struct TransparentTypeResolver; impl TransparentTypeResolver { - pub fn transparent_alias_for_path(path: &Path, generics: &[GenericArgument], library: &Library, params: &GenericParams) -> Option { + /// Attempts to resolve a path as a transparent alias. Even if this function returns None, the + /// caller has also resolved the generics and may need to return them. + pub fn transparent_alias_for_path( + path: &Path, + generics: &[GenericArgument], + library: &Library, + params: &GenericParams, + ) -> Option { let Some(items) = library.get_items(path) else { warn!("Unknown type {path:?}"); return None; @@ -117,9 +150,18 @@ impl TransparentTypeResolver { return None; } - // The type we resolve may itself be transparent, so recurse on it - let resolved_type = item.transparent_alias(library, generics, params)?; - resolved_type.transparent_alias(library, params).or(Some(resolved_type)) + // Only some item types can ever be transparent -- handle them directly (not via `Item`) + let resolved_type = match item { + ItemContainer::Typedef(t) => t.transparent_alias(generics)?, + ItemContainer::Struct(s) => s.transparent_alias(generics)?, + ItemContainer::OpaqueItem(o) => o.transparent_alias(generics)?, + _ => return None, + }; + + // The resolved type may itself be transparent, so recurse on it + resolved_type + .transparent_alias(library, params) + .or(Some(resolved_type)) } pub fn resolve_items(&self, library: &Library, items: &ItemMap) -> ResolvedItems @@ -146,26 +188,39 @@ impl TransparentTypeResolver { } // Functions do not impl Item - pub fn resolve_functions(&self, library: &Library, items: &Vec) -> ResolvedItems { + pub fn resolve_functions( + &self, + library: &Library, + items: &[Function], + ) -> ResolvedItems { let mut functions = Default::default(); - for (i, item) in items.into_iter().enumerate() { + for (i, item) in items.iter().enumerate() { Self::resolve_item(item, i, &mut functions, library); } functions } - pub fn install_functions(&self, mut functions: ResolvedItems, items: &mut Vec) { - for (i, item) in items.into_iter().enumerate() { + pub fn install_functions( + &self, + mut functions: ResolvedItems, + items: &mut [Function], + ) { + for (i, item) in items.iter_mut().enumerate() { Self::install_item(item, i, &mut functions); } } - - fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) { + fn resolve_item(item: &T, i: usize, resolved: &mut ResolvedItems, library: &Library) + where + T: ResolveTransparentTypes, + { if let Some(alias) = item.resolve_transparent_types(library) { resolved.insert(i, alias); } } - fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) { + fn install_item(item: &mut T, i: usize, resolved: &mut ResolvedItems) + where + T: ResolveTransparentTypes, + { if let Some(alias) = resolved.remove(&i) { *item = alias; } From b57741936cbfeeabaa81868938b437d9627b4c26 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 7 Nov 2024 10:43:09 -0800 Subject: [PATCH 12/13] remove noise --- tests/tests.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index de77547c..eebabefb 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -331,18 +331,6 @@ fn test_file(name: &'static str, filename: &'static str) { // Run tests in deduplication priority order. C++ compatibility tests are run first, // otherwise we would lose the C++ compiler run if they were deduplicated. let mut cbindgen_outputs = HashSet::new(); - - run_compile_test( - name, - test, - tmp_dir, - Language::Cxx, - /* cpp_compat = */ false, - None, - &mut HashSet::new(), - false, - ); - for cpp_compat in &[true, false] { for style in &[Style::Type, Style::Tag, Style::Both] { run_compile_test( @@ -358,6 +346,17 @@ fn test_file(name: &'static str, filename: &'static str) { } } + run_compile_test( + name, + test, + tmp_dir, + Language::Cxx, + /* cpp_compat = */ false, + None, + &mut HashSet::new(), + false, + ); + // `Style::Both` should be identical to `Style::Tag` for Cython. let mut cbindgen_outputs = HashSet::new(); for style in &[Style::Type, Style::Tag] { From 99b9f5dc2234deba1e4d86346b76b23e77307a7a Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 7 Nov 2024 14:40:49 -0800 Subject: [PATCH 13/13] compensate for MSRV 1.70 --- src/bindgen/transparent.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/bindgen/transparent.rs b/src/bindgen/transparent.rs index 660e41ae..c948ecd8 100644 --- a/src/bindgen/transparent.rs +++ b/src/bindgen/transparent.rs @@ -8,37 +8,36 @@ use crate::bindgen::ir::{ use crate::bindgen::library::Library; /// Helper trait that makes it easier to work with `Cow` in iterators -pub trait IterCow: Iterator { - /// Maps from `&T` to `Cow<'a, T>` using the provided function. If the function returns `Some` +// NOTE: 'i is the lifetime of the iterator itself, and 't is the lifetime of references it returns +pub trait IterCow<'i, 't: 'i, T: Clone + 't>: Iterator + 'i { + /// Maps from `&T` to `Cow<'t, T>` using the provided function. If the function returns `Some` /// result, it is returned as `Cow::Owned`; otherwise, return the item as `Cow::Borrowed`. - fn cow_map<'a, F, T>(self, f: F) -> impl Iterator> + // NOTE: MSRV 1.70 requires us to return `Box` because support for returning `impl + // Iterator` from trait methods didn't land until 1.75. Which in turn requires the lifetime 'i. + fn cow_map(self, f: F) -> Box> + 'i> where - F: FnMut(&T) -> Option, - T: Clone + 'a, - Self: Iterator; + F: FnMut(&T) -> Option + 'i, + Self: Iterator; /// True if any item is `Cow::Owned` - fn any_owned<'i, 'a: 'i, T>(self) -> bool + fn any_owned(self) -> bool where - T: Clone + 'a, - Self: Iterator>; + Self: Iterator>; } // Blanket implementation for all iterators -impl IterCow for I { - fn cow_map<'a, F, T>(self, mut f: F) -> impl Iterator> +impl<'i, 't: 'i, T: Clone + 't, I: Iterator + 'i> IterCow<'i, 't, T> for I { + fn cow_map(self, mut f: F) -> Box> + 'i> where - F: FnMut(&T) -> Option, - T: Clone + 'a, - Self: Iterator, + F: FnMut(&T) -> Option + 'i, + Self: Iterator, { - self.map(move |item| f(item).map_or_else(|| Cow::Borrowed(item), Cow::Owned)) + Box::new(self.map(move |item| f(item).map_or_else(|| Cow::Borrowed(item), Cow::Owned))) } - fn any_owned<'i, 'a: 'i, T>(mut self) -> bool + fn any_owned(mut self) -> bool where - T: Clone + 'a, - Self: Iterator>, + Self: Iterator>, { self.any(|item| matches!(item, Cow::Owned(_))) }