Skip to content

Commit

Permalink
Deduplicate the code that turns transparent structs into typedefs
Browse files Browse the repository at this point in the history
  • Loading branch information
scovich committed Aug 12, 2024
1 parent 58c6156 commit ba96d90
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 40 deletions.
19 changes: 18 additions & 1 deletion src/bindgen/ir/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Typedef> {
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.
Expand Down
17 changes: 15 additions & 2 deletions src/bindgen/ir/typedef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Path, AnnotationSet>) {
if self.annotations.is_empty() {
return;
Expand Down
18 changes: 0 additions & 18 deletions src/bindgen/language_backend/clike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,24 +540,6 @@ impl LanguageBackend for CLikeLanguageBackend<'_> {
}

fn write_struct<W: Write>(&mut self, out: &mut SourceWriter<W>, 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);

Expand Down
18 changes: 0 additions & 18 deletions src/bindgen/language_backend/cython.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,24 +159,6 @@ impl LanguageBackend for CythonLanguageBackend<'_> {
}

fn write_struct<W: Write>(&mut self, out: &mut SourceWriter<W>, 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);

Expand Down
20 changes: 19 additions & 1 deletion src/bindgen/language_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<W: Write>(
&mut self,
out: &mut SourceWriter<W>,
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<W: Write>(&mut self, out: &mut SourceWriter<W>, b: &Bindings) {
for item in &b.items {
if item
Expand All @@ -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),
Expand Down

0 comments on commit ba96d90

Please sign in to comment.