summaryrefslogtreecommitdiff
path: root/src/codegen/struct_layout.rs
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2021-02-07 19:19:48 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2021-02-07 23:10:28 +0100
commit8ac787a9b4fab937533b964a3ee8d0bff840bf08 (patch)
tree3c69b97cfe86bf5b0f2013331509a5b237b7c097 /src/codegen/struct_layout.rs
parent17476e9f4eee21cf7fe9aee5f5b68538bfcce169 (diff)
codegen: Track union layout more accurately.
Instead of always generating the _bindgen_union_align method (which shouldn't be needed at all for Rust structs, since the struct layout tracker already deals with adding repr(align) as necessary) make sure to visit all fields appropriately to generate the correct alignment.
Diffstat (limited to 'src/codegen/struct_layout.rs')
-rw-r--r--src/codegen/struct_layout.rs39
1 files changed, 25 insertions, 14 deletions
diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs
index 4536e889..2e4b9735 100644
--- a/src/codegen/struct_layout.rs
+++ b/src/codegen/struct_layout.rs
@@ -19,6 +19,7 @@ pub struct StructLayoutTracker<'a> {
comp: &'a CompInfo,
is_packed: bool,
known_type_layout: Option<Layout>,
+ is_rust_union: bool,
latest_offset: usize,
padding_count: usize,
latest_field_layout: Option<Layout>,
@@ -89,12 +90,15 @@ impl<'a> StructLayoutTracker<'a> {
) -> Self {
let known_type_layout = ty.layout(ctx);
let is_packed = comp.is_packed(ctx, known_type_layout.as_ref());
+ let is_rust_union = comp.is_union() &&
+ comp.can_be_rust_union(ctx, known_type_layout.as_ref());
StructLayoutTracker {
name,
ctx,
comp,
is_packed,
known_type_layout,
+ is_rust_union,
latest_offset: 0,
padding_count: 0,
latest_field_layout: None,
@@ -103,6 +107,10 @@ impl<'a> StructLayoutTracker<'a> {
}
}
+ pub fn is_rust_union(&self) -> bool {
+ self.is_rust_union
+ }
+
pub fn saw_vtable(&mut self) {
debug!("saw vtable for {}", self.name);
@@ -143,18 +151,9 @@ impl<'a> StructLayoutTracker<'a> {
// actually generate the dummy alignment.
}
- pub fn saw_union(&mut self, layout: Layout) {
- debug!("saw union for {}: {:?}", self.name, layout);
- self.align_to_latest_field(layout);
-
- self.latest_offset += self.padding_bytes(layout) + layout.size;
- self.latest_field_layout = Some(layout);
- self.max_field_align = cmp::max(self.max_field_align, layout.align);
- }
-
- /// Add a padding field if necessary for a given new field _before_ adding
- /// that field.
- pub fn pad_field(
+ /// Returns a padding field if necessary for a given new field _before_
+ /// adding that field.
+ pub fn saw_field(
&mut self,
field_name: &str,
field_ty: &Type,
@@ -181,15 +180,27 @@ impl<'a> StructLayoutTracker<'a> {
}
}
}
+ self.saw_field_with_layout(field_name, field_layout, field_offset)
+ }
+ pub fn saw_field_with_layout(
+ &mut self,
+ field_name: &str,
+ field_layout: Layout,
+ field_offset: Option<usize>,
+ ) -> Option<proc_macro2::TokenStream> {
let will_merge_with_bitfield = self.align_to_latest_field(field_layout);
+ let is_union = self.comp.is_union();
let padding_bytes = match field_offset {
Some(offset) if offset / 8 > self.latest_offset => {
offset / 8 - self.latest_offset
}
_ => {
- if will_merge_with_bitfield || field_layout.align == 0 {
+ if will_merge_with_bitfield ||
+ field_layout.align == 0 ||
+ is_union
+ {
0
} else if !self.is_packed {
self.padding_bytes(field_layout)
@@ -203,7 +214,7 @@ impl<'a> StructLayoutTracker<'a> {
self.latest_offset += padding_bytes;
- let padding_layout = if self.is_packed {
+ let padding_layout = if self.is_packed || is_union {
None
} else {
// Otherwise the padding is useless.