aboutsummaryrefslogtreecommitdiff
path: root/src/ir/comp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/comp.rs')
-rw-r--r--src/ir/comp.rs197
1 files changed, 109 insertions, 88 deletions
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 52dcddd..a221e52 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -111,11 +111,10 @@ impl Method {
/// Is this a virtual method?
pub fn is_virtual(&self) -> bool {
- match self.kind {
- MethodKind::Virtual { .. } |
- MethodKind::VirtualDestructor { .. } => true,
- _ => false,
- }
+ matches!(
+ self.kind,
+ MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
+ )
}
/// Is this a static method?
@@ -630,7 +629,7 @@ where
bitfield_unit_count,
unit_size_in_bits,
unit_align,
- mem::replace(&mut bitfields_in_unit, vec![]),
+ mem::take(&mut bitfields_in_unit),
packed,
);
@@ -639,15 +638,12 @@ where
offset = 0;
unit_align = 0;
}
- } else {
- if offset != 0 &&
- (bitfield_width == 0 ||
- (offset & (bitfield_align * 8 - 1)) +
- bitfield_width >
- bitfield_size * 8)
- {
- offset = align_to(offset, bitfield_align * 8);
- }
+ } else if offset != 0 &&
+ (bitfield_width == 0 ||
+ (offset & (bitfield_align * 8 - 1)) + bitfield_width >
+ bitfield_size * 8)
+ {
+ offset = align_to(offset, bitfield_align * 8);
}
}
@@ -706,24 +702,24 @@ where
/// after.
#[derive(Debug)]
enum CompFields {
- BeforeComputingBitfieldUnits(Vec<RawField>),
- AfterComputingBitfieldUnits {
+ Before(Vec<RawField>),
+ After {
fields: Vec<Field>,
has_bitfield_units: bool,
},
- ErrorComputingBitfieldUnits,
+ Error,
}
impl Default for CompFields {
fn default() -> CompFields {
- CompFields::BeforeComputingBitfieldUnits(vec![])
+ CompFields::Before(vec![])
}
}
impl CompFields {
fn append_raw_field(&mut self, raw: RawField) {
match *self {
- CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
+ CompFields::Before(ref mut raws) => {
raws.push(raw);
}
_ => {
@@ -736,9 +732,7 @@ impl CompFields {
fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) {
let raws = match *self {
- CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
- mem::replace(raws, vec![])
- }
+ CompFields::Before(ref mut raws) => mem::take(raws),
_ => {
panic!("Already computed bitfield units");
}
@@ -748,25 +742,23 @@ impl CompFields {
match result {
Ok((fields, has_bitfield_units)) => {
- *self = CompFields::AfterComputingBitfieldUnits {
+ *self = CompFields::After {
fields,
has_bitfield_units,
};
}
Err(()) => {
- *self = CompFields::ErrorComputingBitfieldUnits;
+ *self = CompFields::Error;
}
}
}
fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
let fields = match *self {
- CompFields::AfterComputingBitfieldUnits {
- ref mut fields, ..
- } => fields,
+ CompFields::After { ref mut fields, .. } => fields,
// Nothing to do here.
- CompFields::ErrorComputingBitfieldUnits => return,
- CompFields::BeforeComputingBitfieldUnits(_) => {
+ CompFields::Error => return,
+ CompFields::Before(_) => {
panic!("Not yet computed bitfield units.");
}
};
@@ -778,7 +770,7 @@ impl CompFields {
) -> bool {
methods.iter().any(|method| {
let method_name = ctx.resolve_func(method.signature()).name();
- method_name == name || ctx.rust_mangle(&method_name) == name
+ method_name == name || ctx.rust_mangle(method_name) == name
})
}
@@ -820,7 +812,7 @@ impl CompFields {
for field in fields.iter_mut() {
match *field {
Field::DataMember(FieldData { ref mut name, .. }) => {
- if let Some(_) = *name {
+ if name.is_some() {
continue;
}
@@ -858,13 +850,13 @@ impl Trace for CompFields {
T: Tracer,
{
match *self {
- CompFields::ErrorComputingBitfieldUnits => {}
- CompFields::BeforeComputingBitfieldUnits(ref fields) => {
+ CompFields::Error => {}
+ CompFields::Before(ref fields) => {
for f in fields {
tracer.visit_kind(f.ty().into(), EdgeKind::Field);
}
}
- CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
+ CompFields::After { ref fields, .. } => {
for f in fields {
f.trace(context, tracer, &());
}
@@ -900,7 +892,7 @@ pub struct FieldData {
impl FieldMethods for FieldData {
fn name(&self) -> Option<&str> {
- self.name.as_ref().map(|n| &**n)
+ self.name.as_deref()
}
fn ty(&self) -> TypeId {
@@ -908,7 +900,7 @@ impl FieldMethods for FieldData {
}
fn comment(&self) -> Option<&str> {
- self.comment.as_ref().map(|c| &**c)
+ self.comment.as_deref()
}
fn bitfield_width(&self) -> Option<u32> {
@@ -1113,21 +1105,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))
}
@@ -1135,24 +1123,54 @@ impl CompInfo {
/// Get this type's set of fields.
pub fn fields(&self) -> &[Field] {
match self.fields {
- CompFields::ErrorComputingBitfieldUnits => &[],
- CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
- fields
- }
- CompFields::BeforeComputingBitfieldUnits(_) => {
+ CompFields::Error => &[],
+ CompFields::After { ref fields, .. } => fields,
+ CompFields::Before(..) => {
panic!("Should always have computed bitfield units first");
}
}
}
+ fn has_fields(&self) -> bool {
+ match self.fields {
+ CompFields::Error => false,
+ CompFields::After { ref fields, .. } => !fields.is_empty(),
+ CompFields::Before(ref raw_fields) => !raw_fields.is_empty(),
+ }
+ }
+
+ fn each_known_field_layout(
+ &self,
+ ctx: &BindgenContext,
+ mut callback: impl FnMut(Layout),
+ ) {
+ match self.fields {
+ CompFields::Error => {}
+ CompFields::After { ref fields, .. } => {
+ for field in fields.iter() {
+ if let Some(layout) = field.layout(ctx) {
+ callback(layout);
+ }
+ }
+ }
+ CompFields::Before(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,
- CompFields::AfterComputingBitfieldUnits {
- has_bitfield_units,
- ..
+ CompFields::Error => false,
+ CompFields::After {
+ has_bitfield_units, ..
} => has_bitfield_units,
- CompFields::BeforeComputingBitfieldUnits(_) => {
+ CompFields::Before(_) => {
panic!("Should always have computed bitfield units first");
}
}
@@ -1249,6 +1267,7 @@ impl CompInfo {
let mut ci = CompInfo::new(kind);
ci.is_forward_declaration =
location.map_or(true, |cur| match cur.kind() {
+ CXCursor_ParmDecl => true,
CXCursor_StructDecl | CXCursor_UnionDecl |
CXCursor_ClassDecl => !cur.is_definition(),
_ => false,
@@ -1374,21 +1393,26 @@ impl CompInfo {
let inner = Item::parse(cur, Some(potential_id), ctx)
.expect("Inner ClassDecl");
- let inner = inner.expect_type_id(ctx);
+ // If we avoided recursion parsing this type (in
+ // `Item::from_ty_with_id()`), then this might not be a
+ // valid type ID, so check and gracefully handle this.
+ if ctx.resolve_item_fallible(inner).is_some() {
+ let inner = inner.expect_type_id(ctx);
- ci.inner_types.push(inner);
+ ci.inner_types.push(inner);
- // A declaration of an union or a struct without name could
- // also be an unnamed field, unfortunately.
- if cur.spelling().is_empty() &&
- cur.kind() != CXCursor_EnumDecl
- {
- let ty = cur.cur_type();
- let public = cur.public_accessible();
- let offset = cur.offset_of_field().ok();
+ // A declaration of an union or a struct without name
+ // could also be an unnamed field, unfortunately.
+ if cur.spelling().is_empty() &&
+ cur.kind() != CXCursor_EnumDecl
+ {
+ let ty = cur.cur_type();
+ let public = cur.public_accessible();
+ let offset = cur.offset_of_field().ok();
- maybe_anonymous_struct_field =
- Some((inner, ty, public, offset));
+ maybe_anonymous_struct_field =
+ Some((inner, ty, public, offset));
+ }
}
}
CXCursor_PackedAttr => {
@@ -1597,23 +1621,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;
}
}
@@ -1626,10 +1644,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.
@@ -1740,7 +1761,7 @@ impl IsOpaque for CompInfo {
// is a type parameter), then we can't compute bitfield units. We are
// left with no choice but to make the whole struct opaque, or else we
// might generate structs with incorrect sizes and alignments.
- if let CompFields::ErrorComputingBitfieldUnits = self.fields {
+ if let CompFields::Error = self.fields {
return true;
}