diff options
Diffstat (limited to 'src/ir/comp.rs')
-rw-r--r-- | src/ir/comp.rs | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/src/ir/comp.rs b/src/ir/comp.rs index d57c272a..e554f9a8 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -1113,21 +1113,17 @@ impl CompInfo { } // empty union case - if self.fields().is_empty() { + if !self.has_fields() { return None; } let mut max_size = 0; // Don't allow align(0) let mut max_align = 1; - for field in self.fields() { - let field_layout = field.layout(ctx); - - if let Some(layout) = field_layout { - max_size = cmp::max(max_size, layout.size); - max_align = cmp::max(max_align, layout.align); - } - } + self.each_known_field_layout(ctx, |layout| { + max_size = cmp::max(max_size, layout.size); + max_align = cmp::max(max_align, layout.align); + }); Some(Layout::new(max_size, max_align)) } @@ -1139,12 +1135,49 @@ impl CompInfo { CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { fields } - CompFields::BeforeComputingBitfieldUnits(_) => { + CompFields::BeforeComputingBitfieldUnits(..) => { panic!("Should always have computed bitfield units first"); } } } + fn has_fields(&self) -> bool { + match self.fields { + CompFields::ErrorComputingBitfieldUnits => false, + CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { + !fields.is_empty() + } + CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => { + !raw_fields.is_empty() + } + } + } + + fn each_known_field_layout( + &self, + ctx: &BindgenContext, + mut callback: impl FnMut(Layout), + ) { + match self.fields { + CompFields::ErrorComputingBitfieldUnits => return, + CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { + for field in fields.iter() { + if let Some(layout) = field.layout(ctx) { + callback(layout); + } + } + } + CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => { + for field in raw_fields.iter() { + let field_ty = ctx.resolve_type(field.0.ty); + if let Some(layout) = field_ty.layout(ctx) { + callback(layout); + } + } + } + } + } + fn has_bitfields(&self) -> bool { match self.fields { CompFields::ErrorComputingBitfieldUnits => false, @@ -1598,23 +1631,17 @@ impl CompInfo { // Even though `libclang` doesn't expose `#pragma packed(...)`, we can // detect it through its effects. if let Some(parent_layout) = layout { - if self.fields().iter().any(|f| match *f { - Field::Bitfields(ref unit) => { - unit.layout().align > parent_layout.align - } - Field::DataMember(ref data) => { - let field_ty = ctx.resolve_type(data.ty()); - field_ty.layout(ctx).map_or(false, |field_ty_layout| { - field_ty_layout.align > parent_layout.align - }) - } - }) { + let mut packed = false; + self.each_known_field_layout(ctx, |layout| { + packed = packed || layout.align > parent_layout.align; + }); + if packed { info!("Found a struct that was defined within `#pragma packed(...)`"); return true; - } else if self.has_own_virtual_method { - if parent_layout.align == 1 { - return true; - } + } + + if self.has_own_virtual_method && parent_layout.align == 1 { + return true; } } @@ -1627,10 +1654,13 @@ impl CompInfo { } /// Compute this compound structure's bitfield allocation units. - pub fn compute_bitfield_units(&mut self, ctx: &BindgenContext) { - // TODO(emilio): If we could detect #pragma packed here we'd fix layout - // tests in divide-by-zero-in-struct-layout.rs - self.fields.compute_bitfield_units(ctx, self.packed_attr) + pub fn compute_bitfield_units( + &mut self, + ctx: &BindgenContext, + layout: Option<&Layout>, + ) { + let packed = self.is_packed(ctx, layout); + self.fields.compute_bitfield_units(ctx, packed) } /// Assign for each anonymous field a generated name. |