diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 49ae5da8..c2eb9567 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -11,7 +11,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Field, GenericArgument, GenericParams, Item, - ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, + ItemContainer, Path, Repr, ReprAlign, ReprStyle, Type, Typedef, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -150,6 +150,23 @@ impl Struct { } } + /// Attempts to convert this struct to a typedef (only works for transparent structs). + pub fn as_typedef(&self) -> Option { + if self.is_transparent { + // NOTE: A `#[repr(transparent)]` struct with 2+ NZT fields fails to compile, but 0 + // fields is allowed for some strange reason. Don't emit the typedef in that case. + if let Some(field) = self.fields.first() { + return Some(Typedef::new_from_struct_field(self, field)); + } else { + error!( + "Cannot convert empty transparent struct {} to typedef", + self.name() + ); + } + } + None + } + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { // Generic structs can instantiate monomorphs only once they've been // instantiated. See `instantiate_monomorph` for more details. diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 58095878..e775a4e8 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, GenericArgument, GenericParams, Item, ItemContainer, Path, - Type, + AnnotationSet, Cfg, Documentation, Field, GenericArgument, GenericParams, Item, ItemContainer, + Path, Struct, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -70,6 +70,19 @@ impl Typedef { self.aliased.simplify_standard_types(config); } + // Used to convert a transparent Struct to a Typedef. + pub fn new_from_struct_field(item: &Struct, field: &Field) -> Self { + Self { + path: item.path().clone(), + export_name: item.export_name().to_string(), + generic_params: item.generic_params.clone(), + aliased: field.ty.clone(), + cfg: item.cfg().cloned(), + annotations: item.annotations().clone(), + documentation: item.documentation().clone(), + } + } + pub fn transfer_annotations(&mut self, out: &mut HashMap) { if self.annotations.is_empty() { return; diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index 5da079c3..bf5a39fb 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -540,24 +540,6 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { } fn write_struct(&mut self, out: &mut SourceWriter, s: &Struct) { - if s.is_transparent { - let typedef = Typedef { - path: s.path.clone(), - export_name: s.export_name.to_owned(), - generic_params: s.generic_params.clone(), - aliased: s.fields[0].ty.clone(), - cfg: s.cfg.clone(), - annotations: s.annotations.clone(), - documentation: s.documentation.clone(), - }; - self.write_type_def(out, &typedef); - for constant in &s.associated_constants { - out.new_line(); - constant.write(self.config, self, out, Some(s)); - } - return; - } - let condition = s.cfg.to_condition(self.config); condition.write_before(self.config, out); diff --git a/src/bindgen/language_backend/cython.rs b/src/bindgen/language_backend/cython.rs index 5c85b2d0..8497f3cd 100644 --- a/src/bindgen/language_backend/cython.rs +++ b/src/bindgen/language_backend/cython.rs @@ -159,24 +159,6 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } fn write_struct(&mut self, out: &mut SourceWriter, s: &Struct) { - if s.is_transparent { - let typedef = Typedef { - path: s.path.clone(), - export_name: s.export_name.to_owned(), - generic_params: s.generic_params.clone(), - aliased: s.fields[0].ty.clone(), - cfg: s.cfg.clone(), - annotations: s.annotations.clone(), - documentation: s.documentation.clone(), - }; - self.write_type_def(out, &typedef); - for constant in &s.associated_constants { - out.new_line(); - constant.write(self.config, self, out, Some(s)); - } - return; - } - let condition = s.cfg.to_condition(self.config); condition.write_before(self.config, out); diff --git a/src/bindgen/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index adb7d850..065bade2 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -139,6 +139,24 @@ pub trait LanguageBackend: Sized { } } + /// If the struct is transparent, emit a typedef of its NZST field type instead. + fn write_struct_or_typedef( + &mut self, + out: &mut SourceWriter, + s: &Struct, + b: &Bindings, + ) { + if let Some(typedef) = s.as_typedef() { + self.write_type_def(out, &typedef); + for constant in &s.associated_constants { + out.new_line(); + constant.write(&b.config, self, out, Some(s)); + } + } else { + self.write_struct(out, s); + } + } + fn write_items(&mut self, out: &mut SourceWriter, b: &Bindings) { for item in &b.items { if item @@ -155,7 +173,7 @@ pub trait LanguageBackend: Sized { ItemContainer::Constant(..) => unreachable!(), ItemContainer::Static(..) => unreachable!(), ItemContainer::Enum(ref x) => self.write_enum(out, x), - ItemContainer::Struct(ref x) => self.write_struct(out, x), + ItemContainer::Struct(ref x) => self.write_struct_or_typedef(out, x, b), ItemContainer::Union(ref x) => self.write_union(out, x), ItemContainer::OpaqueItem(ref x) => self.write_opaque_item(out, x), ItemContainer::Typedef(ref x) => self.write_type_def(out, x),