From da77ca70b18bacff22098334105096a50a64ab7f Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 31 Oct 2024 14:33:07 -0700 Subject: [PATCH 01/10] Instantiate template structs used as function return values --- src/bindgen/config.rs | 6 +++++ src/bindgen/ir/documentation.rs | 6 ++--- src/bindgen/ir/enumeration.rs | 10 +++++++ src/bindgen/ir/function.rs | 6 +++++ src/bindgen/ir/structure.rs | 10 ++++++- src/bindgen/ir/ty.rs | 48 ++++++++++++++++++++++++++++++++- src/bindgen/ir/typedef.rs | 7 ++++- src/bindgen/ir/union.rs | 11 +++++++- src/bindgen/library.rs | 46 +++++++++++++++++++++++++++++-- 9 files changed, 140 insertions(+), 10 deletions(-) diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 31316503d..0832b8156 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -341,6 +341,12 @@ pub struct ExportConfig { pub renaming_overrides_prefixing: bool, /// Mangling configuration. pub mangle: MangleConfig, + /// Whether to instantiate the struct templates that were emitted, as members of a giant struct + /// with the name optionally overridden by [`instantiate_monomorphs_struct_name`]. This silences + /// warnings and errors for several compiles, notably MSVC. + pub instantiate_monomorphs: bool, + /// The struct name to use when [`instantiate_monomorphs`] is enabled, ignored otherwise. + pub instantiate_monomorphs_struct_name: Option, } /// Mangling-specific configuration. diff --git a/src/bindgen/ir/documentation.rs b/src/bindgen/ir/documentation.rs index e6dba9794..b162524af 100644 --- a/src/bindgen/ir/documentation.rs +++ b/src/bindgen/ir/documentation.rs @@ -4,7 +4,7 @@ use crate::bindgen::utilities::SynAttributeHelpers; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Documentation { pub doc_comment: Vec, } @@ -27,8 +27,6 @@ impl Documentation { } pub fn none() -> Self { - Documentation { - doc_comment: Vec::new(), - } + Self::default() } } diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 2e633a7df..124814db0 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -317,6 +317,16 @@ impl Enum { repr.style != ReprStyle::C } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + if self.is_generic() { + return; + } + for v in &self.variants { + if let VariantBody::Body { ref body, .. } = v.body { + body.find_monomorphs(library, out); + } + } + } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { if self.is_generic() { return; diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 79adfce94..13626db62 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -129,6 +129,12 @@ impl Function { } } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + self.ret.find_monomorphs(library, out, true); + for arg in &self.args { + arg.ty.find_monomorphs(library, out, false); + } + } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { self.ret.add_monomorphs(library, out); for arg in &self.args { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 9b33a15c7..f98ce12f4 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, Documentation, Field, GenericPath, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; @@ -174,6 +174,14 @@ impl Struct { } } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + if self.is_generic() { + return; + } + for field in &self.fields { + field.ty.find_monomorphs(library, out, false); + } + } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 4a41d4cf3..c7580b928 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.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::{GenericArgument, GenericParams, GenericPath, Path}; +use crate::bindgen::ir::{GenericArgument, ItemContainer, GenericParams, GenericPath, Path}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::utilities::IterHelpers; @@ -739,6 +739,52 @@ impl Type { self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out) } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet, is_function_ret_val: bool) { + match *self { + Type::Ptr { ref ty, .. } => ty.find_monomorphs(library, out, false), + Type::Path(ref generic) => { + if !is_function_ret_val || generic.generics().is_empty() { + return; + } + let Some(items) = library.get_items(generic.path()) else { + return; + }; + for item in items { + match item { + // Constants and statics cannot be function return types + ItemContainer::Constant(_) | ItemContainer::Static(_) => {} + // Opaque items cannot be instantiated (doomed to compilation failure) + ItemContainer::OpaqueItem(_) => {} + ItemContainer::Typedef(typedef) => { + // Typedefs can reference concrete types so we need to recurse deeper + typedef.find_monomorphs(library, out, true); + } + ItemContainer::Struct(s) if s.is_transparent => { + if let Some(typedef) = s.as_typedef() { + typedef.find_monomorphs(library, out, true); + } + } + ItemContainer::Struct(_) | ItemContainer::Union(_) | ItemContainer::Enum(_) => { + out.insert(generic.clone()); + } + } + } + } + Type::Primitive(_) => {} + Type::Array(ref ty, _) => ty.find_monomorphs(library, out, false), + Type::FuncPtr { + ref ret, + ref args, + .. + } => { + ret.find_monomorphs(library, out, true); + for (_, ref arg) in args { + arg.find_monomorphs(library, out, false); + } + } + } + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { match *self { Type::Ptr { ref ty, .. } => { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e775a4e80..e2dc50258 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -10,7 +10,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, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, Documentation, Field, GenericPath, GenericArgument, GenericParams, Item, ItemContainer, Path, Struct, Type, }; use crate::bindgen::library::Library; @@ -102,6 +102,11 @@ impl Typedef { } } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet, is_function_ret_val: bool) { + if !self.is_generic() { + self.aliased.find_monomorphs(library, out, is_function_ret_val); + } + } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 410e21a27..7a8907e2f 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, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + AnnotationSet, Cfg, Documentation, Field, GenericPath, GenericArgument, GenericParams, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, }; use crate::bindgen::library::Library; @@ -100,6 +100,15 @@ impl Union { } } + pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + if self.is_generic() { + return; + } + for field in &self.fields { + field.ty.find_monomorphs(library, out, false); + } + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic unions can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f9..47432b3dc 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -10,8 +10,7 @@ use crate::bindgen::config::{Config, Language, SortKey}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::error::Error; -use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; -use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; +use crate::bindgen::ir::{Constant, Enum, Field, Function, Type, Item, GenericPath, ItemContainer, ItemMap, OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::ItemType; @@ -81,6 +80,49 @@ impl Library { let mut dependencies = Dependencies::new(); + if self.config.language == Language::Cxx && self.config.export.instantiate_monomorphs { + let mut found = std::collections::HashSet::new(); + self.structs.for_all_items(|x| { + x.find_monomorphs(&self, &mut found); + }); + self.unions.for_all_items(|x| { + x.find_monomorphs(&self, &mut found); + }); + self.enums.for_all_items(|x| { + x.find_monomorphs(&self, &mut found); + }); + self.typedefs.for_all_items(|x| { + x.find_monomorphs(&self, &mut found, false); + }); + for x in &self.functions { + x.find_monomorphs(&self, &mut found); + } + + // Emit all instantiated monomorphs as fields of a giant struct, which silences warnings + // and errors on several compilers. + let struct_name = match self.config.export.instantiate_monomorphs_struct_name { + Some(ref name) => name, + _ => "__cbindgen_monomorph_struct", + }; + let fields = found.into_iter().enumerate().map(|(i, path)| { + Field::from_name_and_type(format!("field{}", i), Type::Path(path)) + }).collect(); + let monomorph_struct = Struct::new( + Path::new(struct_name), + Default::default(), // no generic params + fields, + false, // no tag field + false, // not an enum body + None, // no special alignment requirements + false, // not transparent + None, // no conf + Default::default(), // no annotations + Default::default(), // no documentation + ); + self.structs.try_insert(monomorph_struct); + Type::Path(GenericPath::new(Path::new(struct_name), vec![])).add_dependencies(&self, &mut dependencies); + } + for function in &self.functions { function.add_dependencies(&self, &mut dependencies); } From fb58826f105e35e028b0e438ceffef52afa1ba4a Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 31 Oct 2024 15:41:43 -0700 Subject: [PATCH 02/10] cleanup --- src/bindgen/config.rs | 12 +++-- src/bindgen/ir/enumeration.rs | 8 ++- src/bindgen/ir/function.rs | 10 ++-- src/bindgen/ir/structure.rs | 12 +++-- src/bindgen/ir/ty.rs | 31 ++++++----- src/bindgen/ir/typedef.rs | 14 +++-- src/bindgen/ir/union.rs | 12 +++-- src/bindgen/library.rs | 98 ++++++++++++++++++++--------------- 8 files changed, 120 insertions(+), 77 deletions(-) diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 0832b8156..a8fbb7ace 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -341,12 +341,14 @@ pub struct ExportConfig { pub renaming_overrides_prefixing: bool, /// Mangling configuration. pub mangle: MangleConfig, - /// Whether to instantiate the struct templates that were emitted, as members of a giant struct - /// with the name optionally overridden by [`instantiate_monomorphs_struct_name`]. This silences - /// warnings and errors for several compiles, notably MSVC. - pub instantiate_monomorphs: bool, + /// Whether to instantiate the monomorphs of template types used as function return values. This + /// is needed for C compatibility, because otherwise compilers warn (gcc/clang) or even reject + /// (MSVC) those function definitions. The compensation is made by emitting a single struct with + /// one field for each monomorphized type. The emitted wrapper struct's name can optionally be + /// overridden by [`return_value_monomorphs_struct_name`]. + pub instantiate_return_value_monomorphs: bool, /// The struct name to use when [`instantiate_monomorphs`] is enabled, ignored otherwise. - pub instantiate_monomorphs_struct_name: Option, + pub return_value_monomorphs_struct_name: Option, } /// Mangling-specific configuration. diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 124814db0..ab464951a 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -317,13 +317,17 @@ impl Enum { repr.style != ReprStyle::C } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + ) { if self.is_generic() { return; } for v in &self.variants { if let VariantBody::Body { ref body, .. } = v.body { - body.find_monomorphs(library, out); + body.find_return_value_monomorphs(library, out); } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 13626db62..e0f9636af 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -129,10 +129,14 @@ impl Function { } } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { - self.ret.find_monomorphs(library, out, true); + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + ) { + self.ret.find_return_value_monomorphs(library, out, true); for arg in &self.args { - arg.ty.find_monomorphs(library, out, false); + arg.ty.find_return_value_monomorphs(library, out, false); } } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index f98ce12f4..ef9ec3083 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -10,8 +10,8 @@ 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, GenericPath, GenericArgument, GenericParams, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, + AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, + GenericPath, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -174,12 +174,16 @@ impl Struct { } } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + ) { if self.is_generic() { return; } for field in &self.fields { - field.ty.find_monomorphs(library, out, false); + field.ty.find_return_value_monomorphs(library, out, false); } } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index c7580b928..d9c74b3c8 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.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::{GenericArgument, ItemContainer, 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; @@ -739,9 +739,14 @@ impl Type { self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out) } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet, is_function_ret_val: bool) { + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + is_function_ret_val: bool, + ) { match *self { - Type::Ptr { ref ty, .. } => ty.find_monomorphs(library, out, false), + Type::Ptr { ref ty, .. } => ty.find_return_value_monomorphs(library, out, false), Type::Path(ref generic) => { if !is_function_ret_val || generic.generics().is_empty() { return; @@ -752,34 +757,34 @@ impl Type { for item in items { match item { // Constants and statics cannot be function return types - ItemContainer::Constant(_) | ItemContainer::Static(_) => {} + ItemContainer::Constant(_) | ItemContainer::Static(_) => {} // Opaque items cannot be instantiated (doomed to compilation failure) ItemContainer::OpaqueItem(_) => {} ItemContainer::Typedef(typedef) => { // Typedefs can reference concrete types so we need to recurse deeper - typedef.find_monomorphs(library, out, true); + typedef.find_return_value_monomorphs(library, out, true); } ItemContainer::Struct(s) if s.is_transparent => { if let Some(typedef) = s.as_typedef() { - typedef.find_monomorphs(library, out, true); + typedef.find_return_value_monomorphs(library, out, true); } } - ItemContainer::Struct(_) | ItemContainer::Union(_) | ItemContainer::Enum(_) => { + ItemContainer::Struct(_) + | ItemContainer::Union(_) + | ItemContainer::Enum(_) => { out.insert(generic.clone()); } } } } Type::Primitive(_) => {} - Type::Array(ref ty, _) => ty.find_monomorphs(library, out, false), + Type::Array(ref ty, _) => ty.find_return_value_monomorphs(library, out, false), Type::FuncPtr { - ref ret, - ref args, - .. + ref ret, ref args, .. } => { - ret.find_monomorphs(library, out, true); + ret.find_return_value_monomorphs(library, out, true); for (_, ref arg) in args { - arg.find_monomorphs(library, out, false); + arg.find_return_value_monomorphs(library, out, false); } } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e2dc50258..e94c86f44 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -10,8 +10,8 @@ use crate::bindgen::config::Config; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericPath, GenericArgument, GenericParams, Item, ItemContainer, - Path, Struct, Type, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, + ItemContainer, Path, Struct, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -102,9 +102,15 @@ impl Typedef { } } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet, is_function_ret_val: bool) { + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + is_function_ret_val: bool, + ) { if !self.is_generic() { - self.aliased.find_monomorphs(library, out, is_function_ret_val); + self.aliased + .find_return_value_monomorphs(library, out, is_function_ret_val); } } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 7a8907e2f..6659b62dd 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -8,8 +8,8 @@ use crate::bindgen::config::{Config, LayoutConfig}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, Documentation, Field, GenericPath, GenericArgument, GenericParams, Item, ItemContainer, - Path, Repr, ReprAlign, ReprStyle, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, + ItemContainer, Path, Repr, ReprAlign, ReprStyle, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -100,12 +100,16 @@ impl Union { } } - pub fn find_monomorphs(&self, library: &Library, out: &mut std::collections::HashSet) { + pub fn find_return_value_monomorphs( + &self, + library: &Library, + out: &mut std::collections::HashSet, + ) { if self.is_generic() { return; } for field in &self.fields { - field.ty.find_monomorphs(library, out, false); + field.ty.find_return_value_monomorphs(library, out, false); } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 47432b3dc..24f20070c 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -10,7 +10,10 @@ use crate::bindgen::config::{Config, Language, SortKey}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::error::Error; -use crate::bindgen::ir::{Constant, Enum, Field, Function, Type, Item, GenericPath, ItemContainer, ItemMap, OpaqueItem, Path, Static, Struct, Typedef, Union}; +use crate::bindgen::ir::{ + Constant, Enum, Field, Function, GenericPath, Item, ItemContainer, ItemMap, OpaqueItem, Path, + Static, Struct, Type, Typedef, Union, +}; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::ItemType; @@ -80,47 +83,10 @@ impl Library { let mut dependencies = Dependencies::new(); - if self.config.language == Language::Cxx && self.config.export.instantiate_monomorphs { - let mut found = std::collections::HashSet::new(); - self.structs.for_all_items(|x| { - x.find_monomorphs(&self, &mut found); - }); - self.unions.for_all_items(|x| { - x.find_monomorphs(&self, &mut found); - }); - self.enums.for_all_items(|x| { - x.find_monomorphs(&self, &mut found); - }); - self.typedefs.for_all_items(|x| { - x.find_monomorphs(&self, &mut found, false); - }); - for x in &self.functions { - x.find_monomorphs(&self, &mut found); - } - - // Emit all instantiated monomorphs as fields of a giant struct, which silences warnings - // and errors on several compilers. - let struct_name = match self.config.export.instantiate_monomorphs_struct_name { - Some(ref name) => name, - _ => "__cbindgen_monomorph_struct", - }; - let fields = found.into_iter().enumerate().map(|(i, path)| { - Field::from_name_and_type(format!("field{}", i), Type::Path(path)) - }).collect(); - let monomorph_struct = Struct::new( - Path::new(struct_name), - Default::default(), // no generic params - fields, - false, // no tag field - false, // not an enum body - None, // no special alignment requirements - false, // not transparent - None, // no conf - Default::default(), // no annotations - Default::default(), // no documentation - ); - self.structs.try_insert(monomorph_struct); - Type::Path(GenericPath::new(Path::new(struct_name), vec![])).add_dependencies(&self, &mut dependencies); + if self.config.language == Language::Cxx + && self.config.export.instantiate_return_value_monomorphs + { + self.instantiate_return_value_monomorphs(&mut dependencies); } for function in &self.functions { @@ -489,4 +455,52 @@ impl Library { x.mangle_paths(&monomorphs); } } + + fn instantiate_return_value_monomorphs(&mut self, dependencies: &mut Dependencies) { + let mut found = std::collections::HashSet::new(); + self.structs.for_all_items(|x| { + x.find_return_value_monomorphs(self, &mut found); + }); + self.unions.for_all_items(|x| { + x.find_return_value_monomorphs(self, &mut found); + }); + self.enums.for_all_items(|x| { + x.find_return_value_monomorphs(self, &mut found); + }); + self.typedefs.for_all_items(|x| { + x.find_return_value_monomorphs(self, &mut found, false); + }); + for x in &self.functions { + x.find_return_value_monomorphs(self, &mut found); + } + + // Emit all instantiated monomorphs as fields of a giant struct, which silences warnings + // and errors on several compilers. + let struct_name = match self.config.export.return_value_monomorphs_struct_name { + Some(ref name) => name, + _ => "__cbindgen_monomorph_struct", + }; + let fields = found + .into_iter() + .enumerate() + .map(|(i, path)| { + Field::from_name_and_type(format!("field{}", i), Type::Path(path)) + }) + .collect(); + let monomorph_struct = Struct::new( + Path::new(struct_name), + Default::default(), // no generic params + fields, + false, // no tag field + false, // not an enum body + None, // no special alignment requirements + false, // not transparent + None, // no conf + Default::default(), // no annotations + Default::default(), // no documentation + ); + self.structs.try_insert(monomorph_struct); + Type::Path(GenericPath::new(Path::new(struct_name), vec![])) + .add_dependencies(self, dependencies); + } } From 8105224ee2d921518b6aa3b196854c496365654a Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 31 Oct 2024 19:43:25 -0700 Subject: [PATCH 03/10] more cleanups --- src/bindgen/ir/enumeration.rs | 9 ++++----- src/bindgen/ir/function.rs | 8 ++------ src/bindgen/ir/structure.rs | 16 +++++++--------- src/bindgen/ir/ty.rs | 13 ++++++------- src/bindgen/ir/typedef.rs | 9 +++++---- src/bindgen/ir/union.rs | 8 +++----- src/bindgen/library.rs | 32 +++++++++++++------------------- 7 files changed, 40 insertions(+), 55 deletions(-) diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index ab464951a..5c6249ded 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::collections::HashSet; use std::io::Write; use syn::ext::IdentExt; @@ -317,20 +318,18 @@ impl Enum { repr.style != ReprStyle::C } - pub fn find_return_value_monomorphs( - &self, - library: &Library, - out: &mut std::collections::HashSet, - ) { + pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { if self.is_generic() { return; } + for v in &self.variants { if let VariantBody::Body { ref body, .. } = v.body { body.find_return_value_monomorphs(library, out); } } } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { if self.is_generic() { return; diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index e0f9636af..2f8bac220 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -2,7 +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::collections::HashMap; +use std::collections::{HashMap, HashSet}; use syn::ext::IdentExt; @@ -129,11 +129,7 @@ impl Function { } } - pub fn find_return_value_monomorphs( - &self, - library: &Library, - out: &mut std::collections::HashSet, - ) { + pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { self.ret.find_return_value_monomorphs(library, out, true); for arg in &self.args { arg.ty.find_return_value_monomorphs(library, out, false); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index ef9ec3083..66acc7d83 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.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::collections::HashSet; use std::io::Write; use syn::ext::IdentExt; @@ -168,24 +169,21 @@ impl Struct { /// Attempts to convert this struct to a typedef (only works for transparent structs). pub fn as_typedef(&self) -> Option { - match self.fields.first() { - Some(field) if self.is_transparent => Some(Typedef::new_from_struct_field(self, field)), - _ => None, - } + let field = self.fields.first()?; + self.is_transparent + .then(|| Typedef::new_from_struct_field(self, field)) } - pub fn find_return_value_monomorphs( - &self, - library: &Library, - out: &mut std::collections::HashSet, - ) { + pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { if self.is_generic() { return; } + for field in &self.fields { field.ty.find_return_value_monomorphs(library, out, false); } } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index d9c74b3c8..bc5d53954 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; +use std::collections::HashSet; use syn::ext::IdentExt; @@ -742,19 +743,17 @@ impl Type { pub fn find_return_value_monomorphs( &self, library: &Library, - out: &mut std::collections::HashSet, - is_function_ret_val: bool, + out: &mut HashSet, + is_return_value: bool, ) { match *self { Type::Ptr { ref ty, .. } => ty.find_return_value_monomorphs(library, out, false), Type::Path(ref generic) => { - if !is_function_ret_val || generic.generics().is_empty() { + if !is_return_value || generic.generics().is_empty() { return; } - let Some(items) = library.get_items(generic.path()) else { - return; - }; - for item in items { + + for item in library.get_items(generic.path()).into_iter().flatten() { match item { // Constants and statics cannot be function return types ItemContainer::Constant(_) | ItemContainer::Static(_) => {} diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e94c86f44..e776b4a5c 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -2,7 +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::collections::HashMap; +use std::collections::{HashMap, HashSet}; use syn::ext::IdentExt; @@ -105,14 +105,15 @@ impl Typedef { pub fn find_return_value_monomorphs( &self, library: &Library, - out: &mut std::collections::HashSet, - is_function_ret_val: bool, + out: &mut HashSet, + is_return_value: bool, ) { if !self.is_generic() { self.aliased - .find_return_value_monomorphs(library, out, is_function_ret_val); + .find_return_value_monomorphs(library, out, is_return_value); } } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 6659b62dd..21d748fd5 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.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::collections::HashSet; use syn::ext::IdentExt; use crate::bindgen::config::{Config, LayoutConfig}; @@ -100,14 +101,11 @@ impl Union { } } - pub fn find_return_value_monomorphs( - &self, - library: &Library, - out: &mut std::collections::HashSet, - ) { + pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { if self.is_generic() { return; } + for field in &self.fields { field.ty.find_return_value_monomorphs(library, out, false); } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 24f20070c..b9423148a 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -2,7 +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::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use crate::bindgen::bindings::Bindings; @@ -457,35 +457,29 @@ impl Library { } fn instantiate_return_value_monomorphs(&mut self, dependencies: &mut Dependencies) { - let mut found = std::collections::HashSet::new(); - self.structs.for_all_items(|x| { - x.find_return_value_monomorphs(self, &mut found); - }); - self.unions.for_all_items(|x| { - x.find_return_value_monomorphs(self, &mut found); - }); - self.enums.for_all_items(|x| { - x.find_return_value_monomorphs(self, &mut found); - }); - self.typedefs.for_all_items(|x| { - x.find_return_value_monomorphs(self, &mut found, false); - }); + let mut found = HashSet::new(); + self.structs + .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + self.unions + .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + self.enums + .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + self.typedefs + .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found, false)); for x in &self.functions { x.find_return_value_monomorphs(self, &mut found); } - // Emit all instantiated monomorphs as fields of a giant struct, which silences warnings + // Emit all instantiated monomorphs as fields of a dummy struct, which silences warnings // and errors on several compilers. let struct_name = match self.config.export.return_value_monomorphs_struct_name { Some(ref name) => name, - _ => "__cbindgen_monomorph_struct", + _ => "__cbindgen_return_value_monomorphs", }; let fields = found .into_iter() .enumerate() - .map(|(i, path)| { - Field::from_name_and_type(format!("field{}", i), Type::Path(path)) - }) + .map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path))) .collect(); let monomorph_struct = Struct::new( Path::new(struct_name), From 12551024091879b83a14bf0760714abce5b72190 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 08:50:49 -0700 Subject: [PATCH 04/10] refactor code, add tests, fix bugs --- src/bindgen/ir/enumeration.rs | 11 +- src/bindgen/ir/function.rs | 15 +-- src/bindgen/ir/structure.rs | 15 +-- src/bindgen/ir/ty.rs | 52 ++------- src/bindgen/ir/typedef.rs | 17 ++- src/bindgen/ir/union.rs | 15 +-- src/bindgen/library.rs | 46 +++----- src/bindgen/monomorph.rs | 109 +++++++++++++++++- tests/expectations/return_value_monomorphs.c | 93 +++++++++++++++ .../return_value_monomorphs.compat.c | 101 ++++++++++++++++ .../expectations/return_value_monomorphs.cpp | 84 ++++++++++++++ .../expectations/return_value_monomorphs.pyx | 85 ++++++++++++++ .../return_value_monomorphs_both.c | 93 +++++++++++++++ .../return_value_monomorphs_both.compat.c | 101 ++++++++++++++++ .../return_value_monomorphs_tag.c | 93 +++++++++++++++ .../return_value_monomorphs_tag.compat.c | 101 ++++++++++++++++ .../return_value_monomorphs_tag.pyx | 85 ++++++++++++++ tests/rust/return_value_monomorphs.rs | 86 ++++++++++++++ tests/rust/return_value_monomorphs.toml | 4 + tests/tests.rs | 3 - 20 files changed, 1084 insertions(+), 125 deletions(-) create mode 100644 tests/expectations/return_value_monomorphs.c create mode 100644 tests/expectations/return_value_monomorphs.compat.c create mode 100644 tests/expectations/return_value_monomorphs.cpp create mode 100644 tests/expectations/return_value_monomorphs.pyx create mode 100644 tests/expectations/return_value_monomorphs_both.c create mode 100644 tests/expectations/return_value_monomorphs_both.compat.c create mode 100644 tests/expectations/return_value_monomorphs_tag.c create mode 100644 tests/expectations/return_value_monomorphs_tag.compat.c create mode 100644 tests/expectations/return_value_monomorphs_tag.pyx create mode 100644 tests/rust/return_value_monomorphs.rs create mode 100644 tests/rust/return_value_monomorphs.toml diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 5c6249ded..0dba6eae8 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.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::collections::HashSet; use std::io::Write; use syn::ext::IdentExt; @@ -18,7 +17,7 @@ use crate::bindgen::ir::{ use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::writer::{ListType, SourceWriter}; @@ -318,14 +317,10 @@ impl Enum { repr.style != ReprStyle::C } - pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { - if self.is_generic() { - return; - } - + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { for v in &self.variants { if let VariantBody::Body { ref body, .. } = v.body { - body.find_return_value_monomorphs(library, out); + body.find_return_value_monomorphs(monomorphs); } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 2f8bac220..ae926328d 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -2,7 +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::collections::{HashMap, HashSet}; +use std::collections::HashMap; use syn::ext::IdentExt; @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, GenericPath, Path, Type}; use crate::bindgen::library::Library; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::utilities::IterHelpers; @@ -47,6 +47,10 @@ impl Function { attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { + if !sig.generics.params.is_empty() { + return Err("Generic functions are not supported".to_owned()); + } + let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?; if sig.variadic.is_some() { args.push(FunctionArgument { @@ -129,11 +133,8 @@ impl Function { } } - pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { - self.ret.find_return_value_monomorphs(library, out, true); - for arg in &self.args { - arg.ty.find_return_value_monomorphs(library, out, false); - } + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { + monomorphs.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty)); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { self.ret.add_monomorphs(library, out); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 66acc7d83..96b9ed23b 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.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::collections::HashSet; use std::io::Write; use syn::ext::IdentExt; @@ -11,12 +10,12 @@ 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, - GenericPath, Item, ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, + AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, Item, + ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::utilities::IterHelpers; @@ -174,13 +173,9 @@ impl Struct { .then(|| Typedef::new_from_struct_field(self, field)) } - pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { - if self.is_generic() { - return; - } - + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { for field in &self.fields { - field.ty.find_return_value_monomorphs(library, out, false); + field.ty.find_return_value_monomorphs(monomorphs, false); } } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index bc5d53954..71db2efe2 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -3,16 +3,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; -use std::collections::HashSet; use syn::ext::IdentExt; use crate::bindgen::config::{Config, Language}; 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::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::utilities::IterHelpers; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -742,49 +741,16 @@ impl Type { pub fn find_return_value_monomorphs( &self, - library: &Library, - out: &mut HashSet, + monomorphs: &mut ReturnValueMonomorphs<'_>, is_return_value: bool, ) { - match *self { - Type::Ptr { ref ty, .. } => ty.find_return_value_monomorphs(library, out, false), - Type::Path(ref generic) => { - if !is_return_value || generic.generics().is_empty() { - return; - } - - for item in library.get_items(generic.path()).into_iter().flatten() { - match item { - // Constants and statics cannot be function return types - ItemContainer::Constant(_) | ItemContainer::Static(_) => {} - // Opaque items cannot be instantiated (doomed to compilation failure) - ItemContainer::OpaqueItem(_) => {} - ItemContainer::Typedef(typedef) => { - // Typedefs can reference concrete types so we need to recurse deeper - typedef.find_return_value_monomorphs(library, out, true); - } - ItemContainer::Struct(s) if s.is_transparent => { - if let Some(typedef) = s.as_typedef() { - typedef.find_return_value_monomorphs(library, out, true); - } - } - ItemContainer::Struct(_) - | ItemContainer::Union(_) - | ItemContainer::Enum(_) => { - out.insert(generic.clone()); - } - } - } - } + match self { + Type::Ptr { ty, .. } => ty.find_return_value_monomorphs(monomorphs, false), + Type::Path(generic) => monomorphs.handle_return_value_path(generic, is_return_value), Type::Primitive(_) => {} - Type::Array(ref ty, _) => ty.find_return_value_monomorphs(library, out, false), - Type::FuncPtr { - ref ret, ref args, .. - } => { - ret.find_return_value_monomorphs(library, out, true); - for (_, ref arg) in args { - arg.find_return_value_monomorphs(library, out, false); - } + Type::Array(ty, _) => ty.find_return_value_monomorphs(monomorphs, false), + Type::FuncPtr { ret, args, .. } => { + monomorphs.handle_function(ret, args.iter().map(|(_, arg)| arg)) } } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index e776b4a5c..ce61a8baa 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -2,7 +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::collections::{HashMap, HashSet}; +use std::collections::HashMap; use syn::ext::IdentExt; @@ -10,12 +10,12 @@ 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, GenericPath, Item, - ItemContainer, Path, Struct, Type, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + Path, Struct, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; /// A type alias that is represented as a C typedef #[derive(Debug, Clone)] @@ -104,14 +104,11 @@ impl Typedef { pub fn find_return_value_monomorphs( &self, - library: &Library, - out: &mut HashSet, + monomorphs: &mut ReturnValueMonomorphs<'_>, is_return_value: bool, ) { - if !self.is_generic() { - self.aliased - .find_return_value_monomorphs(library, out, is_return_value); - } + self.aliased + .find_return_value_monomorphs(monomorphs, is_return_value); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 21d748fd5..9ae8b923c 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -2,19 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::collections::HashSet; use syn::ext::IdentExt; 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, GenericPath, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + Path, Repr, ReprAlign, ReprStyle, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::utilities::IterHelpers; @@ -101,13 +100,9 @@ impl Union { } } - pub fn find_return_value_monomorphs(&self, library: &Library, out: &mut HashSet) { - if self.is_generic() { - return; - } - + pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { for field in &self.fields { - field.ty.find_return_value_monomorphs(library, out, false); + field.ty.find_return_value_monomorphs(monomorphs, false); } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index b9423148a..f4bd0375f 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -2,7 +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::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::path::PathBuf; use crate::bindgen::bindings::Bindings; @@ -11,10 +11,10 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::error::Error; use crate::bindgen::ir::{ - Constant, Enum, Field, Function, GenericPath, Item, ItemContainer, ItemMap, OpaqueItem, Path, - Static, Struct, Type, Typedef, Union, + Constant, Enum, Function, Item, ItemContainer, ItemMap, OpaqueItem, Path, Static, Struct, + Typedef, Union, }; -use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -457,44 +457,26 @@ impl Library { } fn instantiate_return_value_monomorphs(&mut self, dependencies: &mut Dependencies) { - let mut found = HashSet::new(); + let mut monomorphs = ReturnValueMonomorphs::new(self); self.structs - .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); self.unions - .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); self.enums - .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found)); + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs)); self.typedefs - .for_all_items(|x| x.find_return_value_monomorphs(self, &mut found, false)); + .for_all_items(|x| x.find_return_value_monomorphs(&mut monomorphs, false)); for x in &self.functions { - x.find_return_value_monomorphs(self, &mut found); + x.find_return_value_monomorphs(&mut monomorphs); } - // Emit all instantiated monomorphs as fields of a dummy struct, which silences warnings - // and errors on several compilers. let struct_name = match self.config.export.return_value_monomorphs_struct_name { Some(ref name) => name, _ => "__cbindgen_return_value_monomorphs", }; - let fields = found - .into_iter() - .enumerate() - .map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path))) - .collect(); - let monomorph_struct = Struct::new( - Path::new(struct_name), - Default::default(), // no generic params - fields, - false, // no tag field - false, // not an enum body - None, // no special alignment requirements - false, // not transparent - None, // no conf - Default::default(), // no annotations - Default::default(), // no documentation - ); - self.structs.try_insert(monomorph_struct); - Type::Path(GenericPath::new(Path::new(struct_name), vec![])) - .add_dependencies(self, dependencies); + if let Some((struct_name, struct_def)) = monomorphs.into_struct(struct_name) { + self.structs.try_insert(struct_def); + struct_name.add_dependencies(self, dependencies); + } } } diff --git a/src/bindgen/monomorph.rs b/src/bindgen/monomorph.rs index 2dab9cf46..7796b363f 100644 --- a/src/bindgen/monomorph.rs +++ b/src/bindgen/monomorph.rs @@ -2,11 +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::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::mem; use crate::bindgen::ir::{ - Enum, GenericArgument, GenericPath, Item, OpaqueItem, Path, Struct, Typedef, Union, + Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem, + Path, Struct, Type, Typedef, Union, }; use crate::bindgen::library::Library; @@ -145,3 +146,107 @@ impl Monomorphs { mem::take(&mut self.enums) } } + +/// A helper for collecting all function return value momomorphs -- template types returned by +/// functions that can lead to compilation warnings/errors if not explicitly instantiated. +pub struct ReturnValueMonomorphs<'a> { + library: &'a Library, + monomorphs: HashSet, +} + +impl<'a> ReturnValueMonomorphs<'a> { + pub fn new(library: &'a Library) -> Self { + Self { + library, + monomorphs: HashSet::new(), + } + } + + /// Resolve a typedef that is a function return value, specializing it first if needed. + fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) { + if typedef.is_generic() { + let args = generic.generics(); + let aliased = &typedef.aliased; + let mappings = typedef.generic_params.call(typedef.path.name(), args); + let aliased = aliased.specialize(&mappings); + aliased.find_return_value_monomorphs(self, true); + } else { + typedef.find_return_value_monomorphs(self, true); + } + } + + /// Once we find a function return type, what we do with it depends on the type of item it + /// resolves to. Typedefs need to be resolved recursively, while generic structs, unions, and + /// enums are captured in the set of return value monomorphs. + pub fn handle_return_value_path(&mut self, generic: &GenericPath, is_return_value: bool) { + if !is_return_value { + return; + } + + for item in self.library.get_items(generic.path()).into_iter().flatten() { + match item { + // Constants and statics cannot be function return types + ItemContainer::Constant(_) | ItemContainer::Static(_) => {} + // Opaque items cannot be instantiated (doomed to compilation failure) + ItemContainer::OpaqueItem(_) => {} + ItemContainer::Typedef(t) => self.handle_return_value_typedef(t, generic), + ItemContainer::Union(_) | ItemContainer::Enum(_) => { + if !generic.generics().is_empty() { + self.monomorphs.insert(generic.clone()); + } + } + ItemContainer::Struct(s) => { + if let Some(t) = s.as_typedef() { + self.handle_return_value_typedef(t, generic); + } else if !generic.generics().is_empty() { + self.monomorphs.insert(generic.clone()); + } + } + } + } + } + + /// Whenever we encounter a function (or function pointer), we need to check whether its return + /// value is an instantiated generic type (monomorph). + pub fn handle_function<'i>(&mut self, ret: &Type, args: impl IntoIterator) { + ret.find_return_value_monomorphs(self, true); + for arg in args.into_iter() { + arg.find_return_value_monomorphs(self, false); + } + } + + /// Emit all instantiated return value monomorphs as fields of a dummy struct, which silences + /// warnings and errors on several compilers. + pub fn into_struct(self, struct_name: &str) -> Option<(Type, Struct)> { + if self.monomorphs.is_empty() { + return None; + } + + let fields = self + .monomorphs + .into_iter() + .enumerate() + .map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path))) + .collect(); + let doc_comment = vec![ + " Dummy struct emitted by cbindgen to avoid compiler warnings/errors about", + " return type C linkage for template types returned by value from functions", + ]; + let doc_comment = doc_comment.into_iter().map(Into::into).collect(); + let struct_name = GenericPath::new(Path::new(struct_name), vec![]); + let struct_def = Struct::new( + struct_name.path().clone(), + Default::default(), // no generic params + fields, + false, // no tag field + false, // not an enum body + None, // no special alignment requirements + false, // not transparent + None, // no conf + Default::default(), // no annotations + Documentation { doc_comment }, + ); + let struct_name = Type::Path(struct_name); + Some((struct_name, struct_def)) + } +} diff --git a/tests/expectations/return_value_monomorphs.c b/tests/expectations/return_value_monomorphs.c new file mode 100644 index 000000000..7a93dd043 --- /dev/null +++ b/tests/expectations/return_value_monomorphs.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +typedef struct { + int16_t x; +} Foo_i16; + +typedef struct { + int8_t x; +} Foo_i8; + +typedef struct { + int32_t x; +} NotReturnValue_i32; + +typedef struct { + Foo_i8 (*f)(void); + void (*g)(NotReturnValue_i32); +} FooField; + +typedef struct { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef Bar_i8__i32 IntBar_i32; + +typedef struct { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct { + int32_t x; +} Foo_i32; + +typedef Foo_i32 WrapFoo_i32; + +typedef struct { + bool p; + bool q; +} Bar_bool__bool; + +typedef Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct { + int64_t x; +} Foo_i64; + +typedef Foo_i64 Transparent; + +int32_t fnA(void); + +int16_t fnB(void); + +Foo_i16 fnE(void); + +void fnF(FooField f); + +Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); diff --git a/tests/expectations/return_value_monomorphs.compat.c b/tests/expectations/return_value_monomorphs.compat.c new file mode 100644 index 000000000..42ed3728d --- /dev/null +++ b/tests/expectations/return_value_monomorphs.compat.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +typedef struct { + int16_t x; +} Foo_i16; + +typedef struct { + int8_t x; +} Foo_i8; + +typedef struct { + int32_t x; +} NotReturnValue_i32; + +typedef struct { + Foo_i8 (*f)(void); + void (*g)(NotReturnValue_i32); +} FooField; + +typedef struct { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef Bar_i8__i32 IntBar_i32; + +typedef struct { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct { + int32_t x; +} Foo_i32; + +typedef Foo_i32 WrapFoo_i32; + +typedef struct { + bool p; + bool q; +} Bar_bool__bool; + +typedef Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct { + int64_t x; +} Foo_i64; + +typedef Foo_i64 Transparent; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int32_t fnA(void); + +int16_t fnB(void); + +Foo_i16 fnE(void); + +void fnF(FooField f); + +Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs.cpp b/tests/expectations/return_value_monomorphs.cpp new file mode 100644 index 000000000..f949d7fcb --- /dev/null +++ b/tests/expectations/return_value_monomorphs.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +template +struct Foo { + T x; +}; + +template +struct Bar { + P p; + Q q; +}; + +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + Foo field0; + Bar field1; + Bar field2; + Foo field3; + Foo field4; + Bar field5; + Foo field6; + Bar field7; + Foo field8; +}; + +template +struct NotReturnValue { + T x; +}; + +struct FooField { + Foo (*f)(); + void (*g)(NotReturnValue); +}; + +template +using IntBar = Bar; + +using IntBoolBar = IntBar; + +template +using WrapFoo = Foo; + +using BoolBoolBar = Bar; + +using WrapBoolBoolBar = BoolBoolBar; + +using WrapNonZeroInt = int8_t; + +using Transparent = Foo; + +extern "C" { + +int32_t fnA(); + +int16_t fnB(); + +Foo fnE(); + +void fnF(FooField f); + +Bar fnG(); + +IntBar fnH(); + +IntBoolBar fnI(); + +WrapFoo fnJ(); + +WrapBoolBoolBar fnK(); + +Foo fnL(); + +WrapNonZeroInt fnM(); + +Transparent fnN(); + +} // extern "C" diff --git a/tests/expectations/return_value_monomorphs.pyx b/tests/expectations/return_value_monomorphs.pyx new file mode 100644 index 000000000..e2923874d --- /dev/null +++ b/tests/expectations/return_value_monomorphs.pyx @@ -0,0 +1,85 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef struct Foo_i16: + int16_t x; + + ctypedef struct Foo_i8: + int8_t x; + + ctypedef struct NotReturnValue_i32: + int32_t x; + + ctypedef struct FooField: + Foo_i8 (*f)(); + void (*g)(NotReturnValue_i32); + + ctypedef struct Bar_i16__i16: + int16_t p; + int16_t q; + + ctypedef struct Bar_i8__i32: + int8_t p; + int32_t q; + + ctypedef Bar_i8__i32 IntBar_i32; + + ctypedef struct Bar_i8__bool: + int8_t p; + bool q; + + ctypedef Bar_i8__bool IntBar_bool; + + ctypedef IntBar_bool IntBoolBar; + + ctypedef struct Foo_i32: + int32_t x; + + ctypedef Foo_i32 WrapFoo_i32; + + ctypedef struct Bar_bool__bool: + bool p; + bool q; + + ctypedef Bar_bool__bool BoolBoolBar; + + ctypedef BoolBoolBar WrapBoolBoolBar; + + ctypedef struct Foo_bool: + bool x; + + ctypedef int8_t WrapNonZeroInt; + + ctypedef struct Foo_i64: + int64_t x; + + ctypedef Foo_i64 Transparent; + + int32_t fnA(); + + int16_t fnB(); + + Foo_i16 fnE(); + + void fnF(FooField f); + + Bar_i16__i16 fnG(); + + IntBar_i32 fnH(); + + IntBoolBar fnI(); + + WrapFoo_i32 fnJ(); + + WrapBoolBoolBar fnK(); + + Foo_bool fnL(); + + WrapNonZeroInt fnM(); + + Transparent fnN(); diff --git a/tests/expectations/return_value_monomorphs_both.c b/tests/expectations/return_value_monomorphs_both.c new file mode 100644 index 000000000..3356df7d5 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_both.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +typedef struct Foo_i16 { + int16_t x; +} Foo_i16; + +typedef struct Foo_i8 { + int8_t x; +} Foo_i8; + +typedef struct NotReturnValue_i32 { + int32_t x; +} NotReturnValue_i32; + +typedef struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +} FooField; + +typedef struct Bar_i16__i16 { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct Bar_i8__i32 { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef struct Bar_i8__i32 IntBar_i32; + +typedef struct Bar_i8__bool { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct Foo_i32 { + int32_t x; +} Foo_i32; + +typedef struct Foo_i32 WrapFoo_i32; + +typedef struct Bar_bool__bool { + bool p; + bool q; +} Bar_bool__bool; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct Foo_bool { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct Foo_i64 { + int64_t x; +} Foo_i64; + +typedef struct Foo_i64 Transparent; + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); diff --git a/tests/expectations/return_value_monomorphs_both.compat.c b/tests/expectations/return_value_monomorphs_both.compat.c new file mode 100644 index 000000000..d8a52b971 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_both.compat.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +typedef struct Foo_i16 { + int16_t x; +} Foo_i16; + +typedef struct Foo_i8 { + int8_t x; +} Foo_i8; + +typedef struct NotReturnValue_i32 { + int32_t x; +} NotReturnValue_i32; + +typedef struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +} FooField; + +typedef struct Bar_i16__i16 { + int16_t p; + int16_t q; +} Bar_i16__i16; + +typedef struct Bar_i8__i32 { + int8_t p; + int32_t q; +} Bar_i8__i32; + +typedef struct Bar_i8__i32 IntBar_i32; + +typedef struct Bar_i8__bool { + int8_t p; + bool q; +} Bar_i8__bool; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +typedef struct Foo_i32 { + int32_t x; +} Foo_i32; + +typedef struct Foo_i32 WrapFoo_i32; + +typedef struct Bar_bool__bool { + bool p; + bool q; +} Bar_bool__bool; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +typedef struct Foo_bool { + bool x; +} Foo_bool; + +typedef int8_t WrapNonZeroInt; + +typedef struct Foo_i64 { + int64_t x; +} Foo_i64; + +typedef struct Foo_i64 Transparent; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.c b/tests/expectations/return_value_monomorphs_tag.c new file mode 100644 index 000000000..539f57329 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +struct Foo_i16 { + int16_t x; +}; + +struct Foo_i8 { + int8_t x; +}; + +struct NotReturnValue_i32 { + int32_t x; +}; + +struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +}; + +struct Bar_i16__i16 { + int16_t p; + int16_t q; +}; + +struct Bar_i8__i32 { + int8_t p; + int32_t q; +}; + +typedef struct Bar_i8__i32 IntBar_i32; + +struct Bar_i8__bool { + int8_t p; + bool q; +}; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +struct Foo_i32 { + int32_t x; +}; + +typedef struct Foo_i32 WrapFoo_i32; + +struct Bar_bool__bool { + bool p; + bool q; +}; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +struct Foo_bool { + bool x; +}; + +typedef int8_t WrapNonZeroInt; + +struct Foo_i64 { + int64_t x; +}; + +typedef struct Foo_i64 Transparent; + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); diff --git a/tests/expectations/return_value_monomorphs_tag.compat.c b/tests/expectations/return_value_monomorphs_tag.compat.c new file mode 100644 index 000000000..d16567509 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.compat.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +struct Foo_i16 { + int16_t x; +}; + +struct Foo_i8 { + int8_t x; +}; + +struct NotReturnValue_i32 { + int32_t x; +}; + +struct FooField { + struct Foo_i8 (*f)(void); + void (*g)(struct NotReturnValue_i32); +}; + +struct Bar_i16__i16 { + int16_t p; + int16_t q; +}; + +struct Bar_i8__i32 { + int8_t p; + int32_t q; +}; + +typedef struct Bar_i8__i32 IntBar_i32; + +struct Bar_i8__bool { + int8_t p; + bool q; +}; + +typedef struct Bar_i8__bool IntBar_bool; + +typedef IntBar_bool IntBoolBar; + +struct Foo_i32 { + int32_t x; +}; + +typedef struct Foo_i32 WrapFoo_i32; + +struct Bar_bool__bool { + bool p; + bool q; +}; + +typedef struct Bar_bool__bool BoolBoolBar; + +typedef BoolBoolBar WrapBoolBoolBar; + +struct Foo_bool { + bool x; +}; + +typedef int8_t WrapNonZeroInt; + +struct Foo_i64 { + int64_t x; +}; + +typedef struct Foo_i64 Transparent; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int32_t fnA(void); + +int16_t fnB(void); + +struct Foo_i16 fnE(void); + +void fnF(struct FooField f); + +struct Bar_i16__i16 fnG(void); + +IntBar_i32 fnH(void); + +IntBoolBar fnI(void); + +WrapFoo_i32 fnJ(void); + +WrapBoolBoolBar fnK(void); + +struct Foo_bool fnL(void); + +WrapNonZeroInt fnM(void); + +Transparent fnN(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.pyx b/tests/expectations/return_value_monomorphs_tag.pyx new file mode 100644 index 000000000..e2147e6e2 --- /dev/null +++ b/tests/expectations/return_value_monomorphs_tag.pyx @@ -0,0 +1,85 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + cdef struct Foo_i16: + int16_t x; + + cdef struct Foo_i8: + int8_t x; + + cdef struct NotReturnValue_i32: + int32_t x; + + cdef struct FooField: + Foo_i8 (*f)(); + void (*g)(NotReturnValue_i32); + + cdef struct Bar_i16__i16: + int16_t p; + int16_t q; + + cdef struct Bar_i8__i32: + int8_t p; + int32_t q; + + ctypedef Bar_i8__i32 IntBar_i32; + + cdef struct Bar_i8__bool: + int8_t p; + bool q; + + ctypedef Bar_i8__bool IntBar_bool; + + ctypedef IntBar_bool IntBoolBar; + + cdef struct Foo_i32: + int32_t x; + + ctypedef Foo_i32 WrapFoo_i32; + + cdef struct Bar_bool__bool: + bool p; + bool q; + + ctypedef Bar_bool__bool BoolBoolBar; + + ctypedef BoolBoolBar WrapBoolBoolBar; + + cdef struct Foo_bool: + bool x; + + ctypedef int8_t WrapNonZeroInt; + + cdef struct Foo_i64: + int64_t x; + + ctypedef Foo_i64 Transparent; + + int32_t fnA(); + + int16_t fnB(); + + Foo_i16 fnE(); + + void fnF(FooField f); + + Bar_i16__i16 fnG(); + + IntBar_i32 fnH(); + + IntBoolBar fnI(); + + WrapFoo_i32 fnJ(); + + WrapBoolBoolBar fnK(); + + Foo_bool fnL(); + + WrapNonZeroInt fnM(); + + Transparent fnN(); diff --git a/tests/rust/return_value_monomorphs.rs b/tests/rust/return_value_monomorphs.rs new file mode 100644 index 000000000..44ae0cf97 --- /dev/null +++ b/tests/rust/return_value_monomorphs.rs @@ -0,0 +1,86 @@ +#[repr(C)] +struct Foo { + x: T, +} + +#[repr(C)] +struct NotReturnValue { + x: T, +} + +#[repr(C)] +struct FooField { + f: extern "C" fn() -> Foo, + g: extern "C" fn(NotReturnValue), +} + +#[repr(C)] +struct Bar { + p: P, + q: Q, +} + +#[repr(transparent)] +struct Transparent { + x: Foo, +} + +pub type IntBar = Bar; + +pub type IntBoolBar = IntBar; + +pub type WrapFoo = Foo; + +pub type BoolBoolBar = Bar; + +pub type WrapBoolBoolBar = BoolBoolBar; + +pub type WrapNonZeroInt = NonZero; + +// Negatie case: Not generic +#[no_mangle] +pub extern "C" fn fnA() -> i32 { todo!() } + +// Negative case: Transparent and underlying is not a monomorph +#[no_mangle] +pub extern "C" fn fnB() -> NonZero { todo!() } + +// Negative case: cbindgen does not support template functions in the first place +#[no_mangle] +pub extern "C" fn fnC() -> Foo { todo!() } + +// Negative case: Not emitted because opaque, but anyway would fail to compile because Option only has +// a forward declaration. +//#[no_mangle] +//pub extern "C" fn fnD() -> Option { todo!() } + +#[no_mangle] +pub extern "C" fn fnE() -> Foo { todo!() } + +#[no_mangle] +pub extern "C" fn fnF(f: FooField) {} + +#[no_mangle] +pub extern "C" fn fnG() -> Bar { todo!() } + +#[no_mangle] +pub extern "C" fn fnH() -> IntBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnI() -> IntBoolBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnJ() -> WrapFoo { todo!() } + +#[no_mangle] +pub extern "C" fn fnK() -> WrapBoolBoolBar { todo!() } + +#[no_mangle] +pub extern "C" fn fnL() -> Foo { todo!() } + +// Negative case: transparent and underlying is not a template type +#[no_mangle] +pub extern "C" fn fnM() -> WrapNonZeroInt { todo!() } + +#[no_mangle] +pub extern "C" fn fnN() -> Transparent { todo!() } diff --git a/tests/rust/return_value_monomorphs.toml b/tests/rust/return_value_monomorphs.toml new file mode 100644 index 000000000..e2526be54 --- /dev/null +++ b/tests/rust/return_value_monomorphs.toml @@ -0,0 +1,4 @@ +language = "C++" + +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/tests.rs b/tests/tests.rs index eebabefbe..411622370 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -144,9 +144,6 @@ fn compile( command.arg("-Wno-attributes"); // clang warns about unused const variables. command.arg("-Wno-unused-const-variable"); - // clang also warns about returning non-instantiated templates (they could - // be specialized, but they're not so it's fine). - command.arg("-Wno-return-type-c-linkage"); // deprecated warnings should not be errors as it's intended command.arg("-Wno-deprecated-declarations"); From f7161285ac6057c201612bef80eac2a167c4e5fc Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 10:25:00 -0700 Subject: [PATCH 05/10] sort output for stable test behavior --- src/bindgen/monomorph.rs | 7 +++-- .../expectations/return_value_monomorphs.cpp | 28 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/bindgen/monomorph.rs b/src/bindgen/monomorph.rs index 7796b363f..a69865128 100644 --- a/src/bindgen/monomorph.rs +++ b/src/bindgen/monomorph.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::collections::{HashMap, HashSet}; +use std::iter::FromIterator as _; use std::mem; use crate::bindgen::ir::{ @@ -222,8 +223,10 @@ impl<'a> ReturnValueMonomorphs<'a> { return None; } - let fields = self - .monomorphs + // Sort the output so that the struct remains stable across runs (tests want that). + let mut monomorphs = Vec::from_iter(self.monomorphs); + monomorphs.sort(); + let fields = monomorphs .into_iter() .enumerate() .map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path))) diff --git a/tests/expectations/return_value_monomorphs.cpp b/tests/expectations/return_value_monomorphs.cpp index f949d7fcb..04e2b343b 100644 --- a/tests/expectations/return_value_monomorphs.cpp +++ b/tests/expectations/return_value_monomorphs.cpp @@ -4,29 +4,29 @@ #include #include -template -struct Foo { - T x; -}; - template struct Bar { P p; Q q; }; +template +struct Foo { + T x; +}; + /// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about /// return type C linkage for template types returned by value from functions struct __cbindgen_return_value_monomorphs { - Foo field0; - Bar field1; - Bar field2; - Foo field3; - Foo field4; - Bar field5; - Foo field6; - Bar field7; - Foo field8; + Bar field0; + Bar field1; + Bar field2; + Bar field3; + Foo field4; + Foo field5; + Foo field6; + Foo field7; + Foo field8; }; template From 8664b9df870a74cdaf051c14cf05362f51344abb Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 11:05:33 -0700 Subject: [PATCH 06/10] fix one function generics bug, fix remaining unit tests --- src/bindgen/ir/function.rs | 10 +++++++--- tests/expectations/const_generics_char.cpp | 6 ++++++ tests/expectations/const_generics_thru.cpp | 7 +++++++ tests/expectations/must_use.cpp | 6 ++++++ tests/expectations/swift_name.c | 8 +++++--- tests/expectations/swift_name.compat.c | 8 +++++--- tests/expectations/swift_name.cpp | 12 ++++++------ tests/expectations/swift_name.pyx | 8 +++++--- tests/expectations/swift_name_both.c | 8 +++++--- tests/expectations/swift_name_both.compat.c | 8 +++++--- tests/expectations/swift_name_tag.c | 8 +++++--- tests/expectations/swift_name_tag.compat.c | 8 +++++--- tests/expectations/swift_name_tag.pyx | 8 +++++--- tests/rust/const_generics_char.toml | 2 ++ tests/rust/const_generics_thru.toml | 2 ++ tests/rust/must_use.toml | 3 +++ tests/rust/return_value_monomorphs.toml | 2 -- tests/rust/swift_name.rs | 12 +++++++++--- 18 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 tests/rust/const_generics_char.toml create mode 100644 tests/rust/const_generics_thru.toml diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index ae926328d..09b9e8377 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -9,7 +9,9 @@ use syn::ext::IdentExt; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; -use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, GenericPath, Path, Type}; +use crate::bindgen::ir::{ + AnnotationSet, Cfg, Documentation, GenericParams, GenericPath, Path, Type, +}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::{Monomorphs, ReturnValueMonomorphs}; use crate::bindgen::rename::{IdentifierType, RenameRule}; @@ -47,8 +49,10 @@ impl Function { attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { - if !sig.generics.params.is_empty() { - return Err("Generic functions are not supported".to_owned()); + if let Ok(GenericParams(generics)) = GenericParams::load(&sig.generics) { + if !generics.is_empty() { + return Err("Generic functions are not supported".to_owned()); + } } let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?; diff --git a/tests/expectations/const_generics_char.cpp b/tests/expectations/const_generics_char.cpp index 7c5108cfa..4c87fdadd 100644 --- a/tests/expectations/const_generics_char.cpp +++ b/tests/expectations/const_generics_char.cpp @@ -11,6 +11,12 @@ struct TakeUntil { uintptr_t point; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + TakeUntil<0> field0; +}; + extern "C" { TakeUntil<0> until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_thru.cpp b/tests/expectations/const_generics_thru.cpp index de646d975..00fe28bd6 100644 --- a/tests/expectations/const_generics_thru.cpp +++ b/tests/expectations/const_generics_thru.cpp @@ -14,6 +14,13 @@ struct Outer { Inner inner; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + Outer<1> field0; + Outer<2> field1; +}; + extern "C" { Outer<1> one(); diff --git a/tests/expectations/must_use.cpp b/tests/expectations/must_use.cpp index 45333eb4d..35c30c918 100644 --- a/tests/expectations/must_use.cpp +++ b/tests/expectations/must_use.cpp @@ -26,6 +26,12 @@ struct MUST_USE_STRUCT MaybeOwnedPtr { }; }; +/// Dummy struct emitted by cbindgen to avoid compiler warnings/errors about +/// return type C linkage for template types returned by value from functions +struct __cbindgen_return_value_monomorphs { + MaybeOwnedPtr field0; +}; + template struct MUST_USE_STRUCT OwnedPtr { T *ptr; diff --git a/tests/expectations/swift_name.c b/tests/expectations/swift_name.c index 17ec2144f..1dbb279bf 100644 --- a/tests/expectations/swift_name.c +++ b/tests/expectations/swift_name.c @@ -11,6 +11,8 @@ typedef struct { uint8_t times; } SelfTypeTestStruct; +typedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct { Opaque *ptr; } PointerToOpaque; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.compat.c b/tests/expectations/swift_name.compat.c index d018ce833..354617857 100644 --- a/tests/expectations/swift_name.compat.c +++ b/tests/expectations/swift_name.compat.c @@ -11,6 +11,8 @@ typedef struct { uint8_t times; } SelfTypeTestStruct; +typedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct { Opaque *ptr; } PointerToOpaque; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.cpp b/tests/expectations/swift_name.cpp index 56d422c5a..2703c7feb 100644 --- a/tests/expectations/swift_name.cpp +++ b/tests/expectations/swift_name.cpp @@ -6,15 +6,15 @@ #include #include -template -struct Box; - struct Opaque; struct SelfTypeTestStruct { uint8_t times; }; +template +using Foo = const T*; + struct PointerToOpaque { Opaque *ptr; }; @@ -27,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIF void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(Box self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -Box SelfTypeTestStruct_should_not_exist_return_box() CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo SelfTypeTestStruct_should_not_exist_return_box() CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -49,7 +49,7 @@ void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIF void unnamed_argument(SelfTypeTestStruct*); -void free_function_should_not_exist_box(Box boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name.pyx b/tests/expectations/swift_name.pyx index 3c2435a53..860a72301 100644 --- a/tests/expectations/swift_name.pyx +++ b/tests/expectations/swift_name.pyx @@ -14,6 +14,8 @@ cdef extern from *: ctypedef struct SelfTypeTestStruct: uint8_t times; + ctypedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + ctypedef struct PointerToOpaque: Opaque *ptr; @@ -23,9 +25,9 @@ cdef extern from *: void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self); - void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self); + void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self); - SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(); + Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self); @@ -45,7 +47,7 @@ cdef extern from *: void unnamed_argument(SelfTypeTestStruct*); - void free_function_should_not_exist_box(SelfTypeTestStruct *boxed); + void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct); diff --git a/tests/expectations/swift_name_both.c b/tests/expectations/swift_name_both.c index 4911679fa..ec9bc53a6 100644 --- a/tests/expectations/swift_name_both.c +++ b/tests/expectations/swift_name_both.c @@ -11,6 +11,8 @@ typedef struct SelfTypeTestStruct { uint8_t times; } SelfTypeTestStruct; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct PointerToOpaque { struct Opaque *ptr; } PointerToOpaque; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_both.compat.c b/tests/expectations/swift_name_both.compat.c index 592a8c7d5..99dfce345 100644 --- a/tests/expectations/swift_name_both.compat.c +++ b/tests/expectations/swift_name_both.compat.c @@ -11,6 +11,8 @@ typedef struct SelfTypeTestStruct { uint8_t times; } SelfTypeTestStruct; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + typedef struct PointerToOpaque { struct Opaque *ptr; } PointerToOpaque; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.c b/tests/expectations/swift_name_tag.c index 370b88ae2..db534ce4f 100644 --- a/tests/expectations/swift_name_tag.c +++ b/tests/expectations/swift_name_tag.c @@ -11,6 +11,8 @@ struct SelfTypeTestStruct { uint8_t times; }; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + struct PointerToOpaque { struct Opaque *ptr; }; @@ -21,9 +23,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -43,7 +45,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.compat.c b/tests/expectations/swift_name_tag.compat.c index 89b1b2bd1..a27c95761 100644 --- a/tests/expectations/swift_name_tag.compat.c +++ b/tests/expectations/swift_name_tag.compat.c @@ -11,6 +11,8 @@ struct SelfTypeTestStruct { uint8_t times; }; +typedef const struct SelfTypeTestStruct *Foo_SelfTypeTestStruct; + struct PointerToOpaque { struct Opaque *ptr; }; @@ -25,9 +27,9 @@ void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); -void SelfTypeTestStruct_should_not_exist_box(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); +void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); -struct SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); +Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(void) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_return_box()); void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); @@ -47,7 +49,7 @@ void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) void unnamed_argument(struct SelfTypeTestStruct*); -void free_function_should_not_exist_box(struct SelfTypeTestStruct *boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); +void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); diff --git a/tests/expectations/swift_name_tag.pyx b/tests/expectations/swift_name_tag.pyx index 127fb3243..5a3443f65 100644 --- a/tests/expectations/swift_name_tag.pyx +++ b/tests/expectations/swift_name_tag.pyx @@ -14,6 +14,8 @@ cdef extern from *: cdef struct SelfTypeTestStruct: uint8_t times; + ctypedef const SelfTypeTestStruct *Foo_SelfTypeTestStruct; + cdef struct PointerToOpaque: Opaque *ptr; @@ -23,9 +25,9 @@ cdef extern from *: void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self); - void SelfTypeTestStruct_should_not_exist_box(SelfTypeTestStruct *self); + void SelfTypeTestStruct_should_not_exist_box(Foo_SelfTypeTestStruct self); - SelfTypeTestStruct *SelfTypeTestStruct_should_not_exist_return_box(); + Foo_SelfTypeTestStruct SelfTypeTestStruct_should_not_exist_return_box(); void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self); @@ -45,7 +47,7 @@ cdef extern from *: void unnamed_argument(SelfTypeTestStruct*); - void free_function_should_not_exist_box(SelfTypeTestStruct *boxed); + void free_function_should_not_exist_box(Foo_SelfTypeTestStruct boxed); void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct); diff --git a/tests/rust/const_generics_char.toml b/tests/rust/const_generics_char.toml new file mode 100644 index 000000000..135e56c35 --- /dev/null +++ b/tests/rust/const_generics_char.toml @@ -0,0 +1,2 @@ +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/const_generics_thru.toml b/tests/rust/const_generics_thru.toml new file mode 100644 index 000000000..135e56c35 --- /dev/null +++ b/tests/rust/const_generics_thru.toml @@ -0,0 +1,2 @@ +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/must_use.toml b/tests/rust/must_use.toml index 939df10c0..5342bf2d2 100644 --- a/tests/rust/must_use.toml +++ b/tests/rust/must_use.toml @@ -12,3 +12,6 @@ must_use = "MUST_USE_STRUCT" [enum] must_use = "MUST_USE_ENUM" + +[export] +instantiate_return_value_monomorphs = true diff --git a/tests/rust/return_value_monomorphs.toml b/tests/rust/return_value_monomorphs.toml index e2526be54..135e56c35 100644 --- a/tests/rust/return_value_monomorphs.toml +++ b/tests/rust/return_value_monomorphs.toml @@ -1,4 +1,2 @@ -language = "C++" - [export] instantiate_return_value_monomorphs = true diff --git a/tests/rust/swift_name.rs b/tests/rust/swift_name.rs index 01cfdbe6b..808935262 100644 --- a/tests/rust/swift_name.rs +++ b/tests/rust/swift_name.rs @@ -1,3 +1,9 @@ +// A stand-in for Box, since Box is undefined behavior in C++ +#[repr(transparent)] +pub struct Foo { + data: *const T, +} + #[export_name="rust_print_hello_world"] pub extern fn say_hello() { println!("Hello, World!"); @@ -23,13 +29,13 @@ impl SelfTypeTestStruct { #[export_name="SelfTypeTestStruct_should_not_exist_box"] #[no_mangle] - pub extern fn should_not_exist_box(self: Box) { + pub extern fn should_not_exist_box(self: Foo) { println!("should_not_exist_box"); } #[export_name="SelfTypeTestStruct_should_not_exist_return_box"] #[no_mangle] - pub extern fn should_not_exist_box() -> Box { + pub extern fn should_not_exist_box() -> Foo { println!("should_not_exist_box"); } @@ -92,7 +98,7 @@ pub extern fn unnamed_argument(_: &mut SelfTypeTestStruct) { #[no_mangle] #[allow(unused_variables)] -pub extern fn free_function_should_not_exist_box(boxed: Box) { +pub extern fn free_function_should_not_exist_box(boxed: Foo) { println!("free_function_should_not_exist_box"); } From 81a660ee6d0147c96ee5a1c36fe1d424f7f35832 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 11:08:57 -0700 Subject: [PATCH 07/10] improve output on test compilation failure --- tests/tests.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/tests.rs b/tests/tests.rs index 411622370..97bdf21f5 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -186,7 +186,21 @@ fn compile( println!("Running: {:?}", command); let out = command.output().expect("failed to compile"); - assert!(out.status.success(), "Output failed to compile: {:?}", out); + if !out.status.success() { + let stdout = match str::from_utf8(&out.stdout) { + Ok(s) => s.to_string(), + Err(_) => format!("{:?}", out.stdout), + }; + let stderr = match str::from_utf8(&out.stderr) { + Ok(s) => s.to_string(), + Err(_) => format!("{:?}", out.stderr), + }; + println!("Output failed to compile: {:?}", out.status); + println!("=== STDOUT ===\n{}", stdout); + println!("=== STDERR ===\n{}", stderr); + println!("=============="); + assert!(out.status.success()); + } if object.exists() { fs::remove_file(object).unwrap(); From 4b029823567a01d9bace0c1b0048fd4d680ea14b Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 11:18:59 -0700 Subject: [PATCH 08/10] doc comment fixes --- src/bindgen/config.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index a8fbb7ace..23901558b 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -342,12 +342,13 @@ pub struct ExportConfig { /// Mangling configuration. pub mangle: MangleConfig, /// Whether to instantiate the monomorphs of template types used as function return values. This - /// is needed for C compatibility, because otherwise compilers warn (gcc/clang) or even reject - /// (MSVC) those function definitions. The compensation is made by emitting a single struct with - /// one field for each monomorphized type. The emitted wrapper struct's name can optionally be - /// overridden by [`return_value_monomorphs_struct_name`]. + /// is needed for C compatibility, because otherwise compilers warn (`-Wreturn-type-c-linkage` + /// on gcc/clang) or even reject (MSVC) those function definitions. The compensation is made by + /// emitting a single struct with one field for each monomorphized type. The emitted wrapper + /// struct's name can optionally be overridden by [`return_value_monomorphs_struct_name`]. pub instantiate_return_value_monomorphs: bool, - /// The struct name to use when [`instantiate_monomorphs`] is enabled, ignored otherwise. + /// Overrides the struct name to use when [`instantiate_return_value_monomorphs`] is enabled + /// (ignored otherwise). If not specified, the default is `__cbindgen_return_value_monomorphs`. pub return_value_monomorphs_struct_name: Option, } From fe40e242cf4164a2f7909fa59745eb6c8773bc81 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 11:40:55 -0700 Subject: [PATCH 09/10] clippy --- src/bindgen/ir/function.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 09b9e8377..96cd6d8e3 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -49,10 +49,9 @@ impl Function { attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { - if let Ok(GenericParams(generics)) = GenericParams::load(&sig.generics) { - if !generics.is_empty() { - return Err("Generic functions are not supported".to_owned()); - } + let GenericParams(generics) = GenericParams::load(&sig.generics)?; + if !generics.is_empty() { + return Err("Generic functions are not supported".to_owned()); } let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?; From b99b3219ca393771425e7237c15d45de8cdcfcba Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 1 Nov 2024 15:44:05 -0700 Subject: [PATCH 10/10] respect conditional cfg --- src/bindgen/ir/cfg.rs | 10 +-- src/bindgen/ir/enumeration.rs | 10 +-- src/bindgen/ir/function.rs | 4 +- src/bindgen/ir/structure.rs | 8 ++- src/bindgen/ir/typedef.rs | 6 +- src/bindgen/ir/union.rs | 8 ++- src/bindgen/monomorph.rs | 64 +++++++++++++------ tests/expectations/return_value_monomorphs.c | 28 ++++++++ .../return_value_monomorphs.compat.c | 28 ++++++++ .../expectations/return_value_monomorphs.cpp | 38 +++++++++-- .../expectations/return_value_monomorphs.pyx | 23 +++++++ .../return_value_monomorphs_both.c | 28 ++++++++ .../return_value_monomorphs_both.compat.c | 28 ++++++++ .../return_value_monomorphs_tag.c | 28 ++++++++ .../return_value_monomorphs_tag.compat.c | 28 ++++++++ .../return_value_monomorphs_tag.pyx | 23 +++++++ tests/rust/return_value_monomorphs.rs | 30 +++++++-- tests/rust/return_value_monomorphs.toml | 11 ++++ 18 files changed, 356 insertions(+), 47 deletions(-) diff --git a/src/bindgen/ir/cfg.rs b/src/bindgen/ir/cfg.rs index 65de1a2ff..83ea284f3 100644 --- a/src/bindgen/ir/cfg.rs +++ b/src/bindgen/ir/cfg.rs @@ -42,7 +42,7 @@ impl<'a> DefineKey<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum Cfg { Boolean(String), Named(String, String), @@ -129,10 +129,10 @@ impl syn::parse::Parse for Cfg { impl Cfg { pub fn join(cfgs: &[Cfg]) -> Option { - if cfgs.is_empty() { - None - } else { - Some(Cfg::All(cfgs.to_owned())) + match cfgs { + [] => None, + [cfg] => Some(cfg.clone()), + _ => Some(Cfg::All(cfgs.to_owned())), } } diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 0dba6eae8..f7a58ac5b 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -318,11 +318,13 @@ impl Enum { } pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { - for v in &self.variants { - if let VariantBody::Body { ref body, .. } = v.body { - body.find_return_value_monomorphs(monomorphs); + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for v in &self.variants { + if let VariantBody::Body { ref body, .. } = v.body { + body.find_return_value_monomorphs(m); + } } - } + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 96cd6d8e3..de91f6e2d 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -137,7 +137,9 @@ impl Function { } pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { - monomorphs.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty)); + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + m.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty)); + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { self.ret.add_monomorphs(library, out); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 96b9ed23b..d6fa7a685 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -174,9 +174,11 @@ impl Struct { } pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { - for field in &self.fields { - field.ty.find_return_value_monomorphs(monomorphs, false); - } + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for field in &self.fields { + field.ty.find_return_value_monomorphs(m, false); + } + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index ce61a8baa..9c030441e 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -107,8 +107,10 @@ impl Typedef { monomorphs: &mut ReturnValueMonomorphs<'_>, is_return_value: bool, ) { - self.aliased - .find_return_value_monomorphs(monomorphs, is_return_value); + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + self.aliased + .find_return_value_monomorphs(m, is_return_value); + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 9ae8b923c..9779afbf1 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -101,9 +101,11 @@ impl Union { } pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) { - for field in &self.fields { - field.ty.find_return_value_monomorphs(monomorphs, false); - } + monomorphs.with_active_cfg(self.cfg.clone(), |m| { + for field in &self.fields { + field.ty.find_return_value_monomorphs(m, false); + } + }); } pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { diff --git a/src/bindgen/monomorph.rs b/src/bindgen/monomorph.rs index a69865128..6c8584556 100644 --- a/src/bindgen/monomorph.rs +++ b/src/bindgen/monomorph.rs @@ -7,7 +7,7 @@ use std::iter::FromIterator as _; use std::mem; use crate::bindgen::ir::{ - Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem, + Cfg, Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem, Path, Struct, Type, Typedef, Union, }; use crate::bindgen::library::Library; @@ -152,7 +152,8 @@ impl Monomorphs { /// functions that can lead to compilation warnings/errors if not explicitly instantiated. pub struct ReturnValueMonomorphs<'a> { library: &'a Library, - monomorphs: HashSet, + monomorphs: HashSet<(GenericPath, Option)>, + active_cfgs: Vec, } impl<'a> ReturnValueMonomorphs<'a> { @@ -160,22 +161,44 @@ impl<'a> ReturnValueMonomorphs<'a> { Self { library, monomorphs: HashSet::new(), + active_cfgs: Vec::new(), } } - /// Resolve a typedef that is a function return value, specializing it first if needed. - fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) { - if typedef.is_generic() { - let args = generic.generics(); - let aliased = &typedef.aliased; - let mappings = typedef.generic_params.call(typedef.path.name(), args); - let aliased = aliased.specialize(&mappings); - aliased.find_return_value_monomorphs(self, true); + fn insert(&mut self, generic: &GenericPath, cfg: Option) { + if !generic.generics().is_empty() { + self.with_active_cfg(cfg, |m| { + let cfg = Cfg::join(&m.active_cfgs); + m.monomorphs.insert((generic.clone(), cfg)); + }); + } + } + + pub fn with_active_cfg(&mut self, cfg: Option, thunk: impl FnOnce(&mut Self)) { + if let Some(cfg) = cfg { + self.active_cfgs.push(cfg); + thunk(self); + self.active_cfgs.pop(); } else { - typedef.find_return_value_monomorphs(self, true); + thunk(self); } } + /// Resolve a typedef that is a function return value, specializing it first if needed. + fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) { + self.with_active_cfg(typedef.cfg.clone(), |m| { + if typedef.is_generic() { + let args = generic.generics(); + let aliased = &typedef.aliased; + let mappings = typedef.generic_params.call(typedef.path.name(), args); + let aliased = aliased.specialize(&mappings); + aliased.find_return_value_monomorphs(m, true); + } else { + typedef.find_return_value_monomorphs(m, true); + } + }); + } + /// Once we find a function return type, what we do with it depends on the type of item it /// resolves to. Typedefs need to be resolved recursively, while generic structs, unions, and /// enums are captured in the set of return value monomorphs. @@ -191,16 +214,13 @@ impl<'a> ReturnValueMonomorphs<'a> { // Opaque items cannot be instantiated (doomed to compilation failure) ItemContainer::OpaqueItem(_) => {} ItemContainer::Typedef(t) => self.handle_return_value_typedef(t, generic), - ItemContainer::Union(_) | ItemContainer::Enum(_) => { - if !generic.generics().is_empty() { - self.monomorphs.insert(generic.clone()); - } - } + ItemContainer::Union(u) => self.insert(generic, u.cfg), + ItemContainer::Enum(e) => self.insert(generic, e.cfg), ItemContainer::Struct(s) => { if let Some(t) = s.as_typedef() { self.handle_return_value_typedef(t, generic); - } else if !generic.generics().is_empty() { - self.monomorphs.insert(generic.clone()); + } else { + self.insert(generic, s.cfg); } } } @@ -225,11 +245,15 @@ impl<'a> ReturnValueMonomorphs<'a> { // Sort the output so that the struct remains stable across runs (tests want that). let mut monomorphs = Vec::from_iter(self.monomorphs); - monomorphs.sort(); + monomorphs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2)); let fields = monomorphs .into_iter() .enumerate() - .map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path))) + .map(|(i, (path, cfg))| { + let mut f = Field::from_name_and_type(format!("field{}", i), Type::Path(path)); + f.cfg = cfg; + f + }) .collect(); let doc_comment = vec![ " Dummy struct emitted by cbindgen to avoid compiler warnings/errors about", diff --git a/tests/expectations/return_value_monomorphs.c b/tests/expectations/return_value_monomorphs.c index 7a93dd043..e6fe3b9c0 100644 --- a/tests/expectations/return_value_monomorphs.c +++ b/tests/expectations/return_value_monomorphs.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +typedef struct { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef Foo_u16 FooConditional_u16; +#endif + typedef struct { int16_t x; } Foo_i16; @@ -68,6 +82,14 @@ typedef struct { typedef Foo_i64 Transparent; +typedef struct { + uint8_t x; +} Foo_u8; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -91,3 +113,9 @@ Foo_bool fnL(void); WrapNonZeroInt fnM(void); Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +Foo_u8 fnO(void); +#endif + +Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs.compat.c b/tests/expectations/return_value_monomorphs.compat.c index 42ed3728d..96687ec84 100644 --- a/tests/expectations/return_value_monomorphs.compat.c +++ b/tests/expectations/return_value_monomorphs.compat.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +typedef struct { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef Foo_u16 FooConditional_u16; +#endif + typedef struct { int16_t x; } Foo_i16; @@ -68,10 +82,18 @@ typedef struct { typedef Foo_i64 Transparent; +typedef struct { + uint8_t x; +} Foo_u8; + #ifdef __cplusplus extern "C" { #endif // __cplusplus +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -96,6 +118,12 @@ WrapNonZeroInt fnM(void); Transparent fnN(void); +#if defined(DEFINE_FEATURE_1) +Foo_u8 fnO(void); +#endif + +Foo_u8 fnP(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs.cpp b/tests/expectations/return_value_monomorphs.cpp index 04e2b343b..0bf7a1aa2 100644 --- a/tests/expectations/return_value_monomorphs.cpp +++ b/tests/expectations/return_value_monomorphs.cpp @@ -1,3 +1,9 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include @@ -23,12 +29,26 @@ struct __cbindgen_return_value_monomorphs { Bar field2; Bar field3; Foo field4; - Foo field5; - Foo field6; - Foo field7; - Foo field8; +#if defined(DEFINE_FEATURE_1) + Foo field5 +#endif + ; + Foo field6; +#if (defined(DEFINE_FEATURE_2) && defined(DEFINE_FEATURE_1)) + Foo field7 +#endif + ; + Foo field8; + Foo field9; + Foo field10; + Foo field11; }; +#if defined(DEFINE_FEATURE_1) +template +using FooConditional = Foo; +#endif + template struct NotReturnValue { T x; @@ -57,6 +77,10 @@ using Transparent = Foo; extern "C" { +#if defined(DEFINE_FEATURE_2) +FooConditional double_feature(); +#endif + int32_t fnA(); int16_t fnB(); @@ -81,4 +105,10 @@ WrapNonZeroInt fnM(); Transparent fnN(); +#if defined(DEFINE_FEATURE_1) +Foo fnO(); +#endif + +Foo fnP(); + } // extern "C" diff --git a/tests/expectations/return_value_monomorphs.pyx b/tests/expectations/return_value_monomorphs.pyx index e2923874d..09cb8ce96 100644 --- a/tests/expectations/return_value_monomorphs.pyx +++ b/tests/expectations/return_value_monomorphs.pyx @@ -1,3 +1,9 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t cdef extern from *: @@ -6,6 +12,12 @@ cdef extern from *: cdef extern from *: + ctypedef struct Foo_u16: + uint16_t x; + + IF DEFINE_FEATURE_1: + ctypedef Foo_u16 FooConditional_u16; + ctypedef struct Foo_i16: int16_t x; @@ -60,6 +72,12 @@ cdef extern from *: ctypedef Foo_i64 Transparent; + ctypedef struct Foo_u8: + uint8_t x; + + IF DEFINE_FEATURE_2: + FooConditional_u16 double_feature(); + int32_t fnA(); int16_t fnB(); @@ -83,3 +101,8 @@ cdef extern from *: WrapNonZeroInt fnM(); Transparent fnN(); + + IF DEFINE_FEATURE_1: + Foo_u8 fnO(); + + Foo_u8 fnP(); diff --git a/tests/expectations/return_value_monomorphs_both.c b/tests/expectations/return_value_monomorphs_both.c index 3356df7d5..629f71f2e 100644 --- a/tests/expectations/return_value_monomorphs_both.c +++ b/tests/expectations/return_value_monomorphs_both.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +typedef struct Foo_u16 { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + typedef struct Foo_i16 { int16_t x; } Foo_i16; @@ -68,6 +82,14 @@ typedef struct Foo_i64 { typedef struct Foo_i64 Transparent; +typedef struct Foo_u8 { + uint8_t x; +} Foo_u8; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -91,3 +113,9 @@ struct Foo_bool fnL(void); WrapNonZeroInt fnM(void); Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs_both.compat.c b/tests/expectations/return_value_monomorphs_both.compat.c index d8a52b971..8ef152d56 100644 --- a/tests/expectations/return_value_monomorphs_both.compat.c +++ b/tests/expectations/return_value_monomorphs_both.compat.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +typedef struct Foo_u16 { + uint16_t x; +} Foo_u16; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + typedef struct Foo_i16 { int16_t x; } Foo_i16; @@ -68,10 +82,18 @@ typedef struct Foo_i64 { typedef struct Foo_i64 Transparent; +typedef struct Foo_u8 { + uint8_t x; +} Foo_u8; + #ifdef __cplusplus extern "C" { #endif // __cplusplus +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -96,6 +118,12 @@ WrapNonZeroInt fnM(void); Transparent fnN(void); +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.c b/tests/expectations/return_value_monomorphs_tag.c index 539f57329..2bdaf00ae 100644 --- a/tests/expectations/return_value_monomorphs_tag.c +++ b/tests/expectations/return_value_monomorphs_tag.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +struct Foo_u16 { + uint16_t x; +}; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + struct Foo_i16 { int16_t x; }; @@ -68,6 +82,14 @@ struct Foo_i64 { typedef struct Foo_i64 Transparent; +struct Foo_u8 { + uint8_t x; +}; + +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -91,3 +113,9 @@ struct Foo_bool fnL(void); WrapNonZeroInt fnM(void); Transparent fnN(void); + +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); diff --git a/tests/expectations/return_value_monomorphs_tag.compat.c b/tests/expectations/return_value_monomorphs_tag.compat.c index d16567509..54ff29b22 100644 --- a/tests/expectations/return_value_monomorphs_tag.compat.c +++ b/tests/expectations/return_value_monomorphs_tag.compat.c @@ -1,8 +1,22 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + #include #include #include #include +struct Foo_u16 { + uint16_t x; +}; + +#if defined(DEFINE_FEATURE_1) +typedef struct Foo_u16 FooConditional_u16; +#endif + struct Foo_i16 { int16_t x; }; @@ -68,10 +82,18 @@ struct Foo_i64 { typedef struct Foo_i64 Transparent; +struct Foo_u8 { + uint8_t x; +}; + #ifdef __cplusplus extern "C" { #endif // __cplusplus +#if defined(DEFINE_FEATURE_2) +FooConditional_u16 double_feature(void); +#endif + int32_t fnA(void); int16_t fnB(void); @@ -96,6 +118,12 @@ WrapNonZeroInt fnM(void); Transparent fnN(void); +#if defined(DEFINE_FEATURE_1) +struct Foo_u8 fnO(void); +#endif + +struct Foo_u8 fnP(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/return_value_monomorphs_tag.pyx b/tests/expectations/return_value_monomorphs_tag.pyx index e2147e6e2..66509a465 100644 --- a/tests/expectations/return_value_monomorphs_tag.pyx +++ b/tests/expectations/return_value_monomorphs_tag.pyx @@ -1,3 +1,9 @@ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif + + from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t cdef extern from *: @@ -6,6 +12,12 @@ cdef extern from *: cdef extern from *: + cdef struct Foo_u16: + uint16_t x; + + IF DEFINE_FEATURE_1: + ctypedef Foo_u16 FooConditional_u16; + cdef struct Foo_i16: int16_t x; @@ -60,6 +72,12 @@ cdef extern from *: ctypedef Foo_i64 Transparent; + cdef struct Foo_u8: + uint8_t x; + + IF DEFINE_FEATURE_2: + FooConditional_u16 double_feature(); + int32_t fnA(); int16_t fnB(); @@ -83,3 +101,8 @@ cdef extern from *: WrapNonZeroInt fnM(); Transparent fnN(); + + IF DEFINE_FEATURE_1: + Foo_u8 fnO(); + + Foo_u8 fnP(); diff --git a/tests/rust/return_value_monomorphs.rs b/tests/rust/return_value_monomorphs.rs index 44ae0cf97..1e800b63e 100644 --- a/tests/rust/return_value_monomorphs.rs +++ b/tests/rust/return_value_monomorphs.rs @@ -1,30 +1,42 @@ #[repr(C)] -struct Foo { +pub struct Foo { x: T, } #[repr(C)] -struct NotReturnValue { +pub struct NotReturnValue { x: T, } #[repr(C)] -struct FooField { +pub struct FooField { f: extern "C" fn() -> Foo, g: extern "C" fn(NotReturnValue), } #[repr(C)] -struct Bar { +pub struct Bar { p: P, q: Q, } #[repr(transparent)] -struct Transparent { +pub struct Transparent { x: Foo, } +#[cfg(feature = "feature1")] +pub type FooConditional = Foo; + +pub struct Conditional; + +#[cfg(feature = "feature1")] +impl Conditional { + #[no_mangle] + #[cfg(feature = "feature2")] + pub extern "C" fn double_feature() -> FooConditional { todo!() } +} + pub type IntBar = Bar; pub type IntBoolBar = IntBar; @@ -84,3 +96,11 @@ pub extern "C" fn fnM() -> WrapNonZeroInt { todo!() } #[no_mangle] pub extern "C" fn fnN() -> Transparent { todo!() } + +#[no_mangle] +#[cfg(feature = "feature1")] +pub extern "C" fn fnO() -> Foo { todo!() } + +// This one should cause Foo to appear a second time, because the cfg differs +#[no_mangle] +pub extern "C" fn fnP() -> Foo { todo!() } diff --git a/tests/rust/return_value_monomorphs.toml b/tests/rust/return_value_monomorphs.toml index 135e56c35..282d4cfee 100644 --- a/tests/rust/return_value_monomorphs.toml +++ b/tests/rust/return_value_monomorphs.toml @@ -1,2 +1,13 @@ +header = """ +#if 0 +DEF DEFINE_FEATURE_1 = 0 +DEF DEFINE_FEATURE_2 = 0 +#endif +""" + [export] instantiate_return_value_monomorphs = true + +[defines] +"feature = feature1" = "DEFINE_FEATURE_1" +"feature = feature2" = "DEFINE_FEATURE_2"