| //! Compound types (unions and structs) in our intermediate representation. | |
| use super::analysis::Sizedness; | |
| use super::annotations::Annotations; | |
| use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId}; | |
| use super::dot::DotAttributes; | |
| use super::item::{IsOpaque, Item}; | |
| use super::layout::Layout; | |
| use super::template::TemplateParameters; | |
| use super::traversal::{EdgeKind, Trace, Tracer}; | |
| use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; | |
| use crate::callbacks::FieldInfo; | |
| use crate::clang; | |
| use crate::codegen::struct_layout::align_to; | |
| use crate::ir::derive::CanDeriveCopy; | |
| use crate::parse::ParseError; | |
| use crate::HashMap; | |
| use crate::NonCopyUnionStyle; | |
| use std::cmp; | |
| use std::io; | |
| use std::mem; | |
| /// The kind of compound type. | |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] | |
| pub(crate) enum CompKind { | |
| /// A struct. | |
| Struct, | |
| /// A union. | |
| Union, | |
| } | |
| /// The kind of C++ method. | |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] | |
| pub(crate) enum MethodKind { | |
| /// A constructor. We represent it as method for convenience, to avoid code | |
| /// duplication. | |
| Constructor, | |
| /// A destructor. | |
| Destructor, | |
| /// A virtual destructor. | |
| VirtualDestructor { | |
| /// Whether it's pure virtual. | |
| pure_virtual: bool, | |
| }, | |
| /// A static method. | |
| Static, | |
| /// A method with an explicit object parameter. | |
| ExplicitObject, | |
| /// A normal method. | |
| Normal, | |
| /// A virtual method. | |
| Virtual { | |
| /// Whether it's pure virtual. | |
| pure_virtual: bool, | |
| }, | |
| } | |
| impl MethodKind { | |
| /// Is this a destructor method? | |
| pub(crate) fn is_destructor(self) -> bool { | |
| matches!( | |
| self, | |
| MethodKind::Destructor | MethodKind::VirtualDestructor { .. } | |
| ) | |
| } | |
| /// Is this a pure virtual method? | |
| pub(crate) fn is_pure_virtual(self) -> bool { | |
| match self { | |
| MethodKind::Virtual { pure_virtual } | | |
| MethodKind::VirtualDestructor { pure_virtual } => pure_virtual, | |
| _ => false, | |
| } | |
| } | |
| } | |
| /// A struct representing a C++ method. | |
| #[derive(Debug)] | |
| pub(crate) struct Method { | |
| kind: MethodKind, | |
| /// The signature of the method. Take into account this is not a `Type` | |
| /// item, but a `Function` one. | |
| /// | |
| /// This is tricky and probably this field should be renamed. | |
| signature: FunctionId, | |
| is_const: bool, | |
| } | |
| impl Method { | |
| /// Construct a new `Method`. | |
| pub(crate) fn new( | |
| kind: MethodKind, | |
| signature: FunctionId, | |
| is_const: bool, | |
| ) -> Self { | |
| Method { | |
| kind, | |
| signature, | |
| is_const, | |
| } | |
| } | |
| /// What kind of method is this? | |
| pub(crate) fn kind(&self) -> MethodKind { | |
| self.kind | |
| } | |
| /// Is this a constructor? | |
| pub(crate) fn is_constructor(&self) -> bool { | |
| self.kind == MethodKind::Constructor | |
| } | |
| /// Is this a virtual method? | |
| pub(crate) fn is_virtual(&self) -> bool { | |
| matches!( | |
| self.kind, | |
| MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. } | |
| ) | |
| } | |
| /// Is this a static method? | |
| pub(crate) fn is_static(&self) -> bool { | |
| self.kind == MethodKind::Static | |
| } | |
| /// Does this method have an explicit object parameter? | |
| pub(crate) fn is_explicit_object(&self) -> bool { | |
| self.kind == MethodKind::ExplicitObject | |
| } | |
| /// Get the ID for the `Function` signature for this method. | |
| pub(crate) fn signature(&self) -> FunctionId { | |
| self.signature | |
| } | |
| /// Is this a const qualified method? | |
| pub(crate) fn is_const(&self) -> bool { | |
| self.is_const | |
| } | |
| } | |
| /// Methods common to the various field types. | |
| pub(crate) trait FieldMethods { | |
| /// Get the name of this field. | |
| fn name(&self) -> Option<&str>; | |
| /// Get the type of this field. | |
| fn ty(&self) -> TypeId; | |
| /// Get the comment for this field. | |
| #[allow(dead_code)] // Used by trait implementations in Field wrapper types | |
| fn comment(&self) -> Option<&str>; | |
| /// If this is a bitfield, how many bits does it need? | |
| fn bitfield_width(&self) -> Option<u32>; | |
| /// Is this field declared public? | |
| fn is_public(&self) -> bool; | |
| /// Get the annotations for this field. | |
| fn annotations(&self) -> &Annotations; | |
| /// The offset of the field (in bits) | |
| fn offset(&self) -> Option<usize>; | |
| } | |
| /// A contiguous set of logical bitfields that live within the same physical | |
| /// allocation unit. See 9.2.4 [class.bit] in the C++ standard and [section | |
| /// 2.4.II.1 in the Itanium C++ | |
| /// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types). | |
| #[derive(Debug)] | |
| pub(crate) struct BitfieldUnit { | |
| nth: usize, | |
| layout: Layout, | |
| /// The offset of this unit within the struct, in bits, if known. | |
| offset: Option<usize>, | |
| bitfields: Vec<Bitfield>, | |
| } | |
| impl BitfieldUnit { | |
| /// Get the 1-based index of this bitfield unit within its containing | |
| /// struct. Useful for generating a Rust struct's field name for this unit | |
| /// of bitfields. | |
| pub(crate) fn nth(&self) -> usize { | |
| self.nth | |
| } | |
| /// Get the layout within which these bitfields reside. | |
| pub(crate) fn layout(&self) -> Layout { | |
| self.layout | |
| } | |
| /// Get the offset of this unit within the struct, in bits, if known. | |
| pub(crate) fn offset(&self) -> Option<usize> { | |
| self.offset | |
| } | |
| /// Get the bitfields within this unit. | |
| pub(crate) fn bitfields(&self) -> &[Bitfield] { | |
| &self.bitfields | |
| } | |
| } | |
| /// A struct representing a C++ field. | |
| #[derive(Debug)] | |
| pub(crate) enum Field { | |
| /// A normal data member. | |
| DataMember(FieldData), | |
| /// A physical allocation unit containing many logical bitfields. | |
| Bitfields(BitfieldUnit), | |
| } | |
| impl Field { | |
| /// Get this field's layout. | |
| pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { | |
| match *self { | |
| Field::Bitfields(BitfieldUnit { layout, .. }) => Some(layout), | |
| Field::DataMember(ref data) => { | |
| ctx.resolve_type(data.ty).layout(ctx) | |
| } | |
| } | |
| } | |
| } | |
| impl Trace for Field { | |
| type Extra = (); | |
| fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &()) | |
| where | |
| T: Tracer, | |
| { | |
| match *self { | |
| Field::DataMember(ref data) => { | |
| tracer.visit_kind(data.ty.into(), EdgeKind::Field); | |
| } | |
| Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => { | |
| for bf in bitfields { | |
| tracer.visit_kind(bf.ty().into(), EdgeKind::Field); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| impl DotAttributes for Field { | |
| fn dot_attributes<W>( | |
| &self, | |
| ctx: &BindgenContext, | |
| out: &mut W, | |
| ) -> io::Result<()> | |
| where | |
| W: io::Write, | |
| { | |
| match *self { | |
| Field::DataMember(ref data) => data.dot_attributes(ctx, out), | |
| Field::Bitfields(BitfieldUnit { | |
| layout, | |
| ref bitfields, | |
| .. | |
| }) => { | |
| writeln!( | |
| out, | |
| r#"<tr> | |
| <td>bitfield unit</td> | |
| <td> | |
| <table border="0"> | |
| <tr> | |
| <td>unit.size</td><td>{}</td> | |
| </tr> | |
| <tr> | |
| <td>unit.align</td><td>{}</td> | |
| </tr> | |
| "#, | |
| layout.size, layout.align | |
| )?; | |
| for bf in bitfields { | |
| bf.dot_attributes(ctx, out)?; | |
| } | |
| writeln!(out, "</table></td></tr>") | |
| } | |
| } | |
| } | |
| } | |
| impl DotAttributes for FieldData { | |
| fn dot_attributes<W>( | |
| &self, | |
| _ctx: &BindgenContext, | |
| out: &mut W, | |
| ) -> io::Result<()> | |
| where | |
| W: io::Write, | |
| { | |
| writeln!( | |
| out, | |
| "<tr><td>{}</td><td>{:?}</td></tr>", | |
| self.name().unwrap_or("(anonymous)"), | |
| self.ty() | |
| ) | |
| } | |
| } | |
| impl DotAttributes for Bitfield { | |
| fn dot_attributes<W>( | |
| &self, | |
| _ctx: &BindgenContext, | |
| out: &mut W, | |
| ) -> io::Result<()> | |
| where | |
| W: io::Write, | |
| { | |
| writeln!( | |
| out, | |
| "<tr><td>{} : {}</td><td>{:?}</td></tr>", | |
| self.name().unwrap_or("(anonymous)"), | |
| self.width(), | |
| self.ty() | |
| ) | |
| } | |
| } | |
| /// A logical bitfield within some physical bitfield allocation unit. | |
| #[derive(Debug)] | |
| pub(crate) struct Bitfield { | |
| /// Index of the bit within this bitfield's allocation unit where this | |
| /// bitfield's bits begin. | |
| offset_into_unit: usize, | |
| /// The field data for this bitfield. | |
| data: FieldData, | |
| /// Name of the generated Rust getter for this bitfield. | |
| /// | |
| /// Should be assigned before codegen. | |
| getter_name: Option<String>, | |
| /// Name of the generated Rust setter for this bitfield. | |
| /// | |
| /// Should be assigned before codegen. | |
| setter_name: Option<String>, | |
| } | |
| impl Bitfield { | |
| /// Construct a new bitfield. | |
| fn new(offset_into_unit: usize, raw: RawField) -> Bitfield { | |
| assert!(raw.bitfield_width().is_some()); | |
| Bitfield { | |
| offset_into_unit, | |
| data: raw.0, | |
| getter_name: None, | |
| setter_name: None, | |
| } | |
| } | |
| /// Get the index of the bit within this bitfield's allocation unit where | |
| /// this bitfield begins. | |
| pub(crate) fn offset_into_unit(&self) -> usize { | |
| self.offset_into_unit | |
| } | |
| /// Get the bit width of this bitfield. | |
| pub(crate) fn width(&self) -> u32 { | |
| self.data.bitfield_width().unwrap() | |
| } | |
| /// Name of the generated Rust getter for this bitfield. | |
| /// | |
| /// Panics if called before assigning bitfield accessor names or if | |
| /// this bitfield have no name. | |
| pub(crate) fn getter_name(&self) -> &str { | |
| assert!( | |
| self.name().is_some(), | |
| "`Bitfield::getter_name` called on anonymous field" | |
| ); | |
| self.getter_name.as_ref().expect( | |
| "`Bitfield::getter_name` should only be called after \ | |
| assigning bitfield accessor names", | |
| ) | |
| } | |
| /// Name of the generated Rust setter for this bitfield. | |
| /// | |
| /// Panics if called before assigning bitfield accessor names or if | |
| /// this bitfield have no name. | |
| pub(crate) fn setter_name(&self) -> &str { | |
| assert!( | |
| self.name().is_some(), | |
| "`Bitfield::setter_name` called on anonymous field" | |
| ); | |
| self.setter_name.as_ref().expect( | |
| "`Bitfield::setter_name` should only be called \ | |
| after assigning bitfield accessor names", | |
| ) | |
| } | |
| } | |
| impl FieldMethods for Bitfield { | |
| fn name(&self) -> Option<&str> { | |
| self.data.name() | |
| } | |
| fn ty(&self) -> TypeId { | |
| self.data.ty() | |
| } | |
| fn comment(&self) -> Option<&str> { | |
| self.data.comment() | |
| } | |
| fn bitfield_width(&self) -> Option<u32> { | |
| self.data.bitfield_width() | |
| } | |
| fn is_public(&self) -> bool { | |
| self.data.is_public() | |
| } | |
| fn annotations(&self) -> &Annotations { | |
| self.data.annotations() | |
| } | |
| fn offset(&self) -> Option<usize> { | |
| self.data.offset() | |
| } | |
| } | |
| /// A raw field might be either of a plain data member or a bitfield within a | |
| /// bitfield allocation unit, but we haven't processed it and determined which | |
| /// yet (which would involve allocating it into a bitfield unit if it is a | |
| /// bitfield). | |
| #[derive(Debug)] | |
| struct RawField(FieldData); | |
| impl RawField { | |
| /// Construct a new `RawField`. | |
| fn new( | |
| name: Option<String>, | |
| ty: TypeId, | |
| comment: Option<String>, | |
| annotations: Option<Annotations>, | |
| bitfield_width: Option<u32>, | |
| public: bool, | |
| offset: Option<usize>, | |
| ) -> RawField { | |
| RawField(FieldData { | |
| name, | |
| ty, | |
| comment, | |
| annotations: annotations.unwrap_or_default(), | |
| bitfield_width, | |
| public, | |
| offset, | |
| }) | |
| } | |
| } | |
| impl FieldMethods for RawField { | |
| fn name(&self) -> Option<&str> { | |
| self.0.name() | |
| } | |
| fn ty(&self) -> TypeId { | |
| self.0.ty() | |
| } | |
| fn comment(&self) -> Option<&str> { | |
| self.0.comment() | |
| } | |
| fn bitfield_width(&self) -> Option<u32> { | |
| self.0.bitfield_width() | |
| } | |
| fn is_public(&self) -> bool { | |
| self.0.is_public() | |
| } | |
| fn annotations(&self) -> &Annotations { | |
| self.0.annotations() | |
| } | |
| fn offset(&self) -> Option<usize> { | |
| self.0.offset() | |
| } | |
| } | |
| /// Convert the given ordered set of raw fields into a list of either plain data | |
| /// members, and/or bitfield units containing multiple bitfields. | |
| /// | |
| /// If we do not have the layout for a bitfield's type, then we can't reliably | |
| /// compute its allocation unit. In such cases, we return an error. | |
| fn raw_fields_to_fields_and_bitfield_units<I>( | |
| ctx: &BindgenContext, | |
| raw_fields: I, | |
| packed: bool, | |
| ) -> Result<(Vec<Field>, bool), ()> | |
| where | |
| I: IntoIterator<Item = RawField>, | |
| { | |
| let mut raw_fields = raw_fields.into_iter().fuse().peekable(); | |
| let mut fields = vec![]; | |
| let mut bitfield_unit_count = 0; | |
| loop { | |
| // While we have plain old data members, just keep adding them to our | |
| // resulting fields. | |
| while let Some(raw_field) = | |
| raw_fields.next_if(|f| f.bitfield_width().is_none()) | |
| { | |
| fields.push(Field::DataMember(raw_field.0)); | |
| } | |
| let mut bitfields = vec![]; | |
| // Now gather all the consecutive bitfields. Only consecutive bitfields | |
| // may potentially share a bitfield allocation unit with each other in | |
| // the Itanium C++ ABI. | |
| while let Some(raw_field) = | |
| raw_fields.next_if(|f| f.bitfield_width().is_some()) | |
| { | |
| bitfields.push(raw_field); | |
| } | |
| if bitfields.is_empty() { | |
| break; | |
| } | |
| bitfields_to_allocation_units( | |
| ctx, | |
| &mut bitfield_unit_count, | |
| &mut fields, | |
| bitfields, | |
| packed, | |
| )?; | |
| } | |
| assert!( | |
| raw_fields.next().is_none(), | |
| "The above loop should consume all items in `raw_fields`" | |
| ); | |
| Ok((fields, bitfield_unit_count != 0)) | |
| } | |
| /// Given a set of contiguous raw bitfields, group and allocate them into | |
| /// (potentially multiple) bitfield units. | |
| fn bitfields_to_allocation_units<E, I>( | |
| ctx: &BindgenContext, | |
| bitfield_unit_count: &mut usize, | |
| fields: &mut E, | |
| raw_bitfields: I, | |
| packed: bool, | |
| ) -> Result<(), ()> | |
| where | |
| E: Extend<Field>, | |
| I: IntoIterator<Item = RawField>, | |
| { | |
| assert!(ctx.collected_typerefs()); | |
| // NOTE: What follows is reverse-engineered from LLVM's | |
| // lib/AST/RecordLayoutBuilder.cpp | |
| // | |
| // FIXME(emilio): There are some differences between Microsoft and the | |
| // Itanium ABI, but we'll ignore those and stick to Itanium for now. | |
| // | |
| // Also, we need to handle packed bitfields and stuff. | |
| // | |
| // TODO(emilio): Take into account C++'s wide bitfields, and | |
| // packing, sigh. | |
| fn flush_allocation_unit<E>( | |
| fields: &mut E, | |
| bitfield_unit_count: &mut usize, | |
| unit_size_in_bits: usize, | |
| offset: Option<usize>, | |
| bitfields: Vec<Bitfield>, | |
| ) where | |
| E: Extend<Field>, | |
| { | |
| *bitfield_unit_count += 1; | |
| let align = 1; | |
| let size = align_to(unit_size_in_bits, 8) / 8; | |
| let layout = Layout::new(size, align); | |
| fields.extend(Some(Field::Bitfields(BitfieldUnit { | |
| nth: *bitfield_unit_count, | |
| layout, | |
| offset, | |
| bitfields, | |
| }))); | |
| } | |
| // The offset we're in inside the struct, if we know it (we might not know it in presence of | |
| // templates). | |
| let mut known_start_offset = None; | |
| let mut max_align = 0; | |
| let mut unit_size_in_bits = 0; | |
| let mut bitfields_in_unit = vec![]; | |
| // TODO(emilio): Deal with ms_struct bitfield layout for MSVC? | |
| for bitfield in raw_bitfields { | |
| let bitfield_width = bitfield.bitfield_width().unwrap() as usize; | |
| let bitfield_layout = | |
| ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?; | |
| let bitfield_align = bitfield_layout.align; | |
| let bitfield_size = bitfield_layout.size; | |
| if unit_size_in_bits == 0 { | |
| known_start_offset = bitfield.offset(); | |
| } | |
| let mut offset_in_struct = | |
| bitfield.offset().unwrap_or(unit_size_in_bits); | |
| // A zero-width field serves as alignment / padding. | |
| if !packed && | |
| bitfield.offset().is_none() && | |
| offset_in_struct != 0 && | |
| (bitfield_width == 0 || | |
| (offset_in_struct & (bitfield_align * 8 - 1)) + | |
| bitfield_width > | |
| bitfield_size * 8) | |
| { | |
| offset_in_struct = align_to(offset_in_struct, bitfield_align * 8); | |
| } | |
| // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not affect the | |
| // alignment of a structure or union". This makes sense: such bit-fields are only used for | |
| // padding, and we can't perform an un-aligned read of something we can't read because we | |
| // can't even name it. | |
| if bitfield.name().is_some() { | |
| max_align = cmp::max(max_align, bitfield_align); | |
| } | |
| // Always keep all bitfields around. While unnamed bitifields are used | |
| // for padding (and usually not needed hereafter), large unnamed | |
| // bitfields over their types size cause weird allocation size behavior from clang. | |
| // Therefore, all bitfields needed to be kept around in order to check for this | |
| // and make the struct opaque in this case | |
| let bitfield_offset = | |
| offset_in_struct - known_start_offset.unwrap_or(0); | |
| bitfields_in_unit.push(Bitfield::new(bitfield_offset, bitfield)); | |
| unit_size_in_bits = bitfield_offset + bitfield_width; | |
| } | |
| if unit_size_in_bits != 0 { | |
| // Flush the last allocation unit and its bitfields. | |
| flush_allocation_unit( | |
| fields, | |
| bitfield_unit_count, | |
| unit_size_in_bits, | |
| known_start_offset, | |
| bitfields_in_unit, | |
| ); | |
| } | |
| Ok(()) | |
| } | |
| /// A compound structure's fields are initially raw, and have bitfields that | |
| /// have not been grouped into allocation units. During this time, the fields | |
| /// are mutable and we build them up during parsing. | |
| /// | |
| /// Then, once resolving typerefs is completed, we compute all structs' fields' | |
| /// bitfield allocation units, and they remain frozen and immutable forever | |
| /// after. | |
| #[derive(Debug)] | |
| enum CompFields { | |
| Before(Vec<RawField>), | |
| After { | |
| fields: Vec<Field>, | |
| has_bitfield_units: bool, | |
| }, | |
| Error, | |
| } | |
| impl Default for CompFields { | |
| fn default() -> CompFields { | |
| CompFields::Before(vec![]) | |
| } | |
| } | |
| impl CompFields { | |
| fn append_raw_field(&mut self, raw: RawField) { | |
| match *self { | |
| CompFields::Before(ref mut raws) => { | |
| raws.push(raw); | |
| } | |
| _ => { | |
| panic!( | |
| "Must not append new fields after computing bitfield allocation units" | |
| ); | |
| } | |
| } | |
| } | |
| fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) { | |
| let raws = match *self { | |
| CompFields::Before(ref mut raws) => mem::take(raws), | |
| _ => { | |
| panic!("Already computed bitfield units"); | |
| } | |
| }; | |
| let result = raw_fields_to_fields_and_bitfield_units(ctx, raws, packed); | |
| match result { | |
| Ok((fields, has_bitfield_units)) => { | |
| *self = CompFields::After { | |
| fields, | |
| has_bitfield_units, | |
| }; | |
| } | |
| Err(()) => { | |
| *self = CompFields::Error; | |
| } | |
| } | |
| } | |
| fn assign_field_names( | |
| &mut self, | |
| ctx: &BindgenContext, | |
| canonical_type_name: &str, | |
| methods: &[Method], | |
| ) { | |
| let fields = match *self { | |
| CompFields::After { ref mut fields, .. } => fields, | |
| // Nothing to do here. | |
| CompFields::Error => return, | |
| CompFields::Before(_) => { | |
| panic!("Not yet computed bitfield units."); | |
| } | |
| }; | |
| for field in fields.iter_mut() { | |
| match field { | |
| Field::DataMember(FieldData { name, ty, .. }) => { | |
| if let Some(original_name) = name.as_deref() { | |
| let maybe_rename = ctx.options().last_callback(|cb| { | |
| cb.field_name(FieldInfo { | |
| type_name: canonical_type_name, | |
| field_name: original_name, | |
| field_type_name: ctx.resolve_type(*ty).name(), | |
| }) | |
| }); | |
| if let Some(new_name) = maybe_rename { | |
| *name = Some(new_name); | |
| } | |
| } | |
| } | |
| Field::Bitfields(BitfieldUnit { bitfields, .. }) => { | |
| for bitfield in bitfields.iter_mut() { | |
| if let Some(original_name) = bitfield.name() { | |
| let maybe_rename = | |
| ctx.options().last_callback(|cb| { | |
| cb.field_name(FieldInfo { | |
| type_name: canonical_type_name, | |
| field_name: original_name, | |
| field_type_name: ctx | |
| .resolve_type(bitfield.ty()) | |
| .name(), | |
| }) | |
| }); | |
| if let Some(new_name) = maybe_rename { | |
| bitfield.data.name = Some(new_name); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fn has_method( | |
| methods: &[Method], | |
| ctx: &BindgenContext, | |
| name: &str, | |
| ) -> bool { | |
| methods.iter().any(|method| { | |
| let method_name = ctx.resolve_func(method.signature()).name(); | |
| method_name == name || ctx.rust_mangle(method_name) == name | |
| }) | |
| } | |
| struct AccessorNamesPair { | |
| getter: String, | |
| setter: String, | |
| } | |
| let mut accessor_names: HashMap<String, AccessorNamesPair> = fields | |
| .iter() | |
| .flat_map(|field| match *field { | |
| Field::Bitfields(ref bu) => &*bu.bitfields, | |
| Field::DataMember(_) => &[], | |
| }) | |
| .filter_map(|bitfield| bitfield.name()) | |
| .map(|bitfield_name| { | |
| let bitfield_name = bitfield_name.to_string(); | |
| let getter = { | |
| let mut getter = | |
| ctx.rust_mangle(&bitfield_name).to_string(); | |
| if has_method(methods, ctx, &getter) { | |
| getter.push_str("_bindgen_bitfield"); | |
| } | |
| getter | |
| }; | |
| let setter = { | |
| let setter = format!("set_{bitfield_name}"); | |
| let mut setter = ctx.rust_mangle(&setter).to_string(); | |
| if has_method(methods, ctx, &setter) { | |
| setter.push_str("_bindgen_bitfield"); | |
| } | |
| setter | |
| }; | |
| (bitfield_name, AccessorNamesPair { getter, setter }) | |
| }) | |
| .collect(); | |
| let mut anon_field_counter = 0; | |
| for field in fields.iter_mut() { | |
| match *field { | |
| Field::DataMember(FieldData { ref mut name, .. }) => { | |
| if name.is_some() { | |
| continue; | |
| } | |
| anon_field_counter += 1; | |
| *name = Some(format!( | |
| "{}{anon_field_counter}", | |
| ctx.options().anon_fields_prefix, | |
| )); | |
| } | |
| Field::Bitfields(ref mut bu) => { | |
| for bitfield in &mut bu.bitfields { | |
| if bitfield.name().is_none() { | |
| continue; | |
| } | |
| if let Some(AccessorNamesPair { getter, setter }) = | |
| accessor_names.remove(bitfield.name().unwrap()) | |
| { | |
| bitfield.getter_name = Some(getter); | |
| bitfield.setter_name = Some(setter); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /// Return the flex array member for the struct/class, if any. | |
| /// | |
| /// This method recursively checks if the last field is either: | |
| /// 1. An incomplete array (direct FAM) | |
| /// 2. A struct/union that itself has a FAM (nested FAM) | |
| fn flex_array_member(&self, ctx: &BindgenContext) -> Option<TypeId> { | |
| let fields = match self { | |
| CompFields::Before(_) => panic!("raw fields"), | |
| CompFields::After { fields, .. } => fields, | |
| CompFields::Error => return None, // panic? | |
| }; | |
| match fields.last()? { | |
| Field::Bitfields(..) => None, | |
| Field::DataMember(FieldData { ty, .. }) => { | |
| let resolved_ty = ctx.resolve_type(*ty); | |
| // Check if it's an incomplete array first | |
| if let Some(item) = resolved_ty.is_incomplete_array(ctx) { | |
| return Some(item.expect_type_id(ctx)); | |
| } | |
| // Check if it's a compound type with a FAM (need to resolve through type refs) | |
| let canonical_ty = resolved_ty.canonical_type(ctx); | |
| if let super::ty::TypeKind::Comp(ref comp) = canonical_ty.kind() | |
| { | |
| return comp.flex_array_member(ctx); | |
| } | |
| None | |
| } | |
| } | |
| } | |
| } | |
| impl Trace for CompFields { | |
| type Extra = (); | |
| fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &()) | |
| where | |
| T: Tracer, | |
| { | |
| match *self { | |
| CompFields::Error => {} | |
| CompFields::Before(ref fields) => { | |
| for f in fields { | |
| tracer.visit_kind(f.ty().into(), EdgeKind::Field); | |
| } | |
| } | |
| CompFields::After { ref fields, .. } => { | |
| for f in fields { | |
| f.trace(context, tracer, &()); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /// Common data shared across different field types. | |
| #[derive(Clone, Debug)] | |
| pub(crate) struct FieldData { | |
| /// The name of the field, empty if it's an unnamed bitfield width. | |
| name: Option<String>, | |
| /// The inner type. | |
| ty: TypeId, | |
| /// The doc comment on the field if any. | |
| comment: Option<String>, | |
| /// Annotations for this field, or the default. | |
| annotations: Annotations, | |
| /// If this field is a bitfield, and how many bits does it contain if it is. | |
| bitfield_width: Option<u32>, | |
| /// If the C++ field is declared `public` | |
| public: bool, | |
| /// The offset of the field (in bits) | |
| offset: Option<usize>, | |
| } | |
| impl FieldMethods for FieldData { | |
| fn name(&self) -> Option<&str> { | |
| self.name.as_deref() | |
| } | |
| fn ty(&self) -> TypeId { | |
| self.ty | |
| } | |
| fn comment(&self) -> Option<&str> { | |
| self.comment.as_deref() | |
| } | |
| fn bitfield_width(&self) -> Option<u32> { | |
| self.bitfield_width | |
| } | |
| fn is_public(&self) -> bool { | |
| self.public | |
| } | |
| fn annotations(&self) -> &Annotations { | |
| &self.annotations | |
| } | |
| fn offset(&self) -> Option<usize> { | |
| self.offset | |
| } | |
| } | |
| impl FieldData { | |
| /// Get this field's documentation comment, if it has any, already preprocessed | |
| /// and with the right indentation. Returns `None` if comment generation is disabled. | |
| pub(crate) fn doc_comment(&self, ctx: &BindgenContext) -> Option<String> { | |
| if !ctx.options().generate_comments { | |
| return None; | |
| } | |
| self.comment | |
| .as_ref() | |
| .map(|comment| ctx.options().process_comment(comment)) | |
| } | |
| } | |
| /// The kind of inheritance a base class is using. | |
| #[derive(Clone, Debug, PartialEq, Eq)] | |
| pub(crate) enum BaseKind { | |
| /// Normal inheritance, like: | |
| /// | |
| /// ```cpp | |
| /// class A : public B {}; | |
| /// ``` | |
| Normal, | |
| /// Virtual inheritance, like: | |
| /// | |
| /// ```cpp | |
| /// class A: public virtual B {}; | |
| /// ``` | |
| Virtual, | |
| } | |
| /// A base class. | |
| #[derive(Clone, Debug)] | |
| pub(crate) struct Base { | |
| /// The type of this base class. | |
| pub(crate) ty: TypeId, | |
| /// The kind of inheritance we're doing. | |
| pub(crate) kind: BaseKind, | |
| /// Name of the field in which this base should be stored. | |
| pub(crate) field_name: String, | |
| /// Whether this base is inherited from publicly. | |
| pub(crate) is_pub: bool, | |
| } | |
| impl Base { | |
| /// Whether this base class is inheriting virtually. | |
| pub(crate) fn is_virtual(&self) -> bool { | |
| self.kind == BaseKind::Virtual | |
| } | |
| /// Whether this base class should have it's own field for storage. | |
| pub(crate) fn requires_storage(&self, ctx: &BindgenContext) -> bool { | |
| // Virtual bases are already taken into account by the vtable | |
| // pointer. | |
| // | |
| // FIXME(emilio): Is this always right? | |
| if self.is_virtual() { | |
| return false; | |
| } | |
| // NB: We won't include zero-sized types in our base chain because they | |
| // would contribute to our size given the dummy field we insert for | |
| // zero-sized types. | |
| if self.ty.is_zero_sized(ctx) { | |
| return false; | |
| } | |
| true | |
| } | |
| /// Whether this base is inherited from publicly. | |
| pub(crate) fn is_public(&self) -> bool { | |
| self.is_pub | |
| } | |
| } | |
| /// A compound type. | |
| /// | |
| /// Either a struct or union, a compound type is built up from the combination | |
| /// of fields which also are associated with their own (potentially compound) | |
| /// type. | |
| #[derive(Debug)] | |
| pub(crate) struct CompInfo { | |
| /// Whether this is a struct or a union. | |
| kind: CompKind, | |
| /// The members of this struct or union. | |
| fields: CompFields, | |
| /// The abstract template parameters of this class. Note that these are NOT | |
| /// concrete template arguments, and should always be a | |
| /// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see | |
| /// `TypeKind::TemplateInstantiation`. | |
| template_params: Vec<TypeId>, | |
| /// The method declarations inside this class, if in C++ mode. | |
| methods: Vec<Method>, | |
| /// The different constructors this struct or class contains. | |
| constructors: Vec<FunctionId>, | |
| /// The destructor of this type. The bool represents whether this destructor | |
| /// is virtual. | |
| destructor: Option<(MethodKind, FunctionId)>, | |
| /// Vector of classes this one inherits from. | |
| base_members: Vec<Base>, | |
| /// The inner types that were declared inside this class, in something like: | |
| /// | |
| /// ```c++ | |
| /// class Foo { | |
| /// typedef int FooTy; | |
| /// struct Bar { | |
| /// int baz; | |
| /// }; | |
| /// } | |
| /// | |
| /// static Foo::Bar const = {3}; | |
| /// ``` | |
| inner_types: Vec<TypeId>, | |
| /// Set of static constants declared inside this class. | |
| inner_vars: Vec<VarId>, | |
| /// Whether this type should generate an vtable (TODO: Should be able to | |
| /// look at the virtual methods and ditch this field). | |
| has_own_virtual_method: bool, | |
| /// Whether this type has destructor. | |
| has_destructor: bool, | |
| /// Whether this type has a base type with more than one member. | |
| /// | |
| /// TODO: We should be able to compute this. | |
| has_nonempty_base: bool, | |
| /// If this type has a template parameter which is not a type (e.g.: a | |
| /// `size_t`) | |
| has_non_type_template_params: bool, | |
| /// Whether this type has a bit field member whose width couldn't be | |
| /// evaluated (e.g. if it depends on a template parameter). We generate an | |
| /// opaque type in this case. | |
| has_unevaluable_bit_field_width: bool, | |
| /// Whether we saw `__attribute__((packed))` on or within this type. | |
| packed_attr: bool, | |
| /// Used to know if we've found an opaque attribute that could cause us to | |
| /// generate a type with invalid layout. This is explicitly used to avoid us | |
| /// generating bad alignments when parsing types like `max_align_t`. | |
| /// | |
| /// It's not clear what the behavior should be here, if generating the item | |
| /// and pray, or behave as an opaque type. | |
| found_unknown_attr: bool, | |
| /// Used to indicate when a struct has been forward declared. Usually used | |
| /// in headers so that APIs can't modify them directly. | |
| is_forward_declaration: bool, | |
| } | |
| impl CompInfo { | |
| /// Construct a new compound type. | |
| pub(crate) fn new(kind: CompKind) -> Self { | |
| CompInfo { | |
| kind, | |
| fields: CompFields::default(), | |
| template_params: vec![], | |
| methods: vec![], | |
| constructors: vec![], | |
| destructor: None, | |
| base_members: vec![], | |
| inner_types: vec![], | |
| inner_vars: vec![], | |
| has_own_virtual_method: false, | |
| has_destructor: false, | |
| has_nonempty_base: false, | |
| has_non_type_template_params: false, | |
| has_unevaluable_bit_field_width: false, | |
| packed_attr: false, | |
| found_unknown_attr: false, | |
| is_forward_declaration: false, | |
| } | |
| } | |
| /// Compute the layout of this type. | |
| /// | |
| /// This is called as a fallback under some circumstances where LLVM doesn't | |
| /// give us the correct layout. | |
| /// | |
| /// If we're a union without known layout, we try to compute it from our | |
| /// members. This is not ideal, but clang fails to report the size for these | |
| /// kind of unions, see `test/headers/template_union.hpp` | |
| pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { | |
| // We can't do better than clang here, sorry. | |
| if self.kind == CompKind::Struct { | |
| return None; | |
| } | |
| // By definition, we don't have the right layout information here if | |
| // we're a forward declaration. | |
| if self.is_forward_declaration() { | |
| return None; | |
| } | |
| // empty union case | |
| if !self.has_fields() { | |
| return None; | |
| } | |
| let mut max_size = 0; | |
| // Don't allow align(0) | |
| let mut max_align = 1; | |
| 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)) | |
| } | |
| /// Get this type's set of fields. | |
| pub(crate) fn fields(&self) -> &[Field] { | |
| match self.fields { | |
| CompFields::Error => &[], | |
| CompFields::After { ref fields, .. } => fields, | |
| CompFields::Before(..) => { | |
| panic!("Should always have computed bitfield units first"); | |
| } | |
| } | |
| } | |
| /// Return the flex array member and its element type if any | |
| pub(crate) fn flex_array_member( | |
| &self, | |
| ctx: &BindgenContext, | |
| ) -> Option<TypeId> { | |
| self.fields.flex_array_member(ctx) | |
| } | |
| 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 { | |
| if let Some(layout) = field.layout(ctx) { | |
| callback(layout); | |
| } | |
| } | |
| } | |
| CompFields::Before(ref raw_fields) => { | |
| for field in raw_fields { | |
| let field_ty = ctx.resolve_type(field.0.ty); | |
| if let Some(layout) = field_ty.layout(ctx) { | |
| callback(layout); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /// Returns whether we have any bitfield within the struct. | |
| pub(crate) fn has_bitfields(&self) -> bool { | |
| match self.fields { | |
| CompFields::Error => false, | |
| CompFields::After { | |
| has_bitfield_units, .. | |
| } => has_bitfield_units, | |
| CompFields::Before(_) => { | |
| panic!("Should always have computed bitfield units first"); | |
| } | |
| } | |
| } | |
| /// Returns whether we have a too large bitfield unit, in which case we may | |
| /// not be able to derive some of the things we should be able to normally | |
| /// derive. | |
| pub(crate) fn has_too_large_bitfield_unit(&self) -> bool { | |
| if !self.has_bitfields() { | |
| return false; | |
| } | |
| self.fields().iter().any(|field| match *field { | |
| Field::DataMember(..) => false, | |
| Field::Bitfields(ref unit) => { | |
| unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT | |
| } | |
| }) | |
| } | |
| /// Does this type have any template parameters that aren't types | |
| /// (e.g. int)? | |
| pub(crate) fn has_non_type_template_params(&self) -> bool { | |
| self.has_non_type_template_params | |
| } | |
| /// Do we see a virtual function during parsing? | |
| /// Get the `has_own_virtual_method` boolean. | |
| pub(crate) fn has_own_virtual_method(&self) -> bool { | |
| self.has_own_virtual_method | |
| } | |
| /// Did we see a destructor when parsing this type? | |
| pub(crate) fn has_own_destructor(&self) -> bool { | |
| self.has_destructor | |
| } | |
| /// Get this type's set of methods. | |
| pub(crate) fn methods(&self) -> &[Method] { | |
| &self.methods | |
| } | |
| /// Get this type's set of constructors. | |
| pub(crate) fn constructors(&self) -> &[FunctionId] { | |
| &self.constructors | |
| } | |
| /// Get this type's destructor. | |
| pub(crate) fn destructor(&self) -> Option<(MethodKind, FunctionId)> { | |
| self.destructor | |
| } | |
| /// What kind of compound type is this? | |
| pub(crate) fn kind(&self) -> CompKind { | |
| self.kind | |
| } | |
| /// Is this a union? | |
| pub(crate) fn is_union(&self) -> bool { | |
| self.kind() == CompKind::Union | |
| } | |
| /// The set of types that this one inherits from. | |
| pub(crate) fn base_members(&self) -> &[Base] { | |
| &self.base_members | |
| } | |
| /// Construct a new compound type from a Clang type. | |
| pub(crate) fn from_ty( | |
| potential_id: ItemId, | |
| ty: &clang::Type, | |
| location: Option<clang::Cursor>, | |
| ctx: &mut BindgenContext, | |
| ) -> Result<Self, ParseError> { | |
| use clang_sys::*; | |
| assert!( | |
| ty.template_args().is_none(), | |
| "We handle template instantiations elsewhere" | |
| ); | |
| let mut cursor = ty.declaration(); | |
| let mut kind = Self::kind_from_cursor(&cursor); | |
| if kind.is_err() { | |
| if let Some(location) = location { | |
| kind = Self::kind_from_cursor(&location); | |
| cursor = location; | |
| } | |
| } | |
| let kind = kind?; | |
| debug!("CompInfo::from_ty({kind:?}, {cursor:?})"); | |
| 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, | |
| }); | |
| let mut maybe_anonymous_struct_field = None; | |
| cursor.visit(|cur| { | |
| if cur.kind() != CXCursor_FieldDecl { | |
| if let Some((ty, clang_ty, public, offset)) = | |
| maybe_anonymous_struct_field.take() | |
| { | |
| if cur.kind() == CXCursor_TypedefDecl && | |
| cur.typedef_type().unwrap().canonical_type() == | |
| clang_ty | |
| { | |
| // Typedefs of anonymous structs appear later in the ast | |
| // than the struct itself, that would otherwise be an | |
| // anonymous field. Detect that case here, and do | |
| // nothing. | |
| } else { | |
| let field = RawField::new( | |
| None, ty, None, None, None, public, offset, | |
| ); | |
| ci.fields.append_raw_field(field); | |
| } | |
| } | |
| } | |
| match cur.kind() { | |
| CXCursor_FieldDecl => { | |
| if let Some((ty, clang_ty, public, offset)) = | |
| maybe_anonymous_struct_field.take() | |
| { | |
| let mut used = false; | |
| cur.visit(|child| { | |
| if child.cur_type() == clang_ty { | |
| used = true; | |
| } | |
| CXChildVisit_Continue | |
| }); | |
| if !used { | |
| let field = RawField::new( | |
| None, ty, None, None, None, public, offset, | |
| ); | |
| ci.fields.append_raw_field(field); | |
| } | |
| } | |
| let bit_width = if cur.is_bit_field() { | |
| let width = cur.bit_width(); | |
| // Make opaque type if the bit width couldn't be | |
| // evaluated. | |
| if width.is_none() { | |
| ci.has_unevaluable_bit_field_width = true; | |
| return CXChildVisit_Break; | |
| } | |
| width | |
| } else { | |
| None | |
| }; | |
| let field_type = Item::from_ty_or_ref( | |
| cur.cur_type(), | |
| cur, | |
| Some(potential_id), | |
| ctx, | |
| ); | |
| let comment = cur.raw_comment(); | |
| let annotations = Annotations::new(&cur); | |
| let name = cur.spelling(); | |
| let is_public = cur.public_accessible(); | |
| let offset = cur.offset_of_field().ok(); | |
| // Name can be empty if there are bitfields, for example, | |
| // see tests/headers/struct_with_bitfields.h | |
| assert!( | |
| !name.is_empty() || bit_width.is_some(), | |
| "Empty field name?" | |
| ); | |
| let name = if name.is_empty() { None } else { Some(name) }; | |
| let field = RawField::new( | |
| name, | |
| field_type, | |
| comment, | |
| annotations, | |
| bit_width, | |
| is_public, | |
| offset, | |
| ); | |
| ci.fields.append_raw_field(field); | |
| // No we look for things like attributes and stuff. | |
| cur.visit(|cur| { | |
| if cur.kind() == CXCursor_UnexposedAttr { | |
| ci.found_unknown_attr = true; | |
| } | |
| CXChildVisit_Continue | |
| }); | |
| } | |
| CXCursor_UnexposedAttr => { | |
| ci.found_unknown_attr = true; | |
| } | |
| CXCursor_EnumDecl | | |
| CXCursor_TypeAliasDecl | | |
| CXCursor_TypeAliasTemplateDecl | | |
| CXCursor_TypedefDecl | | |
| CXCursor_StructDecl | | |
| CXCursor_UnionDecl | | |
| CXCursor_ClassTemplate | | |
| CXCursor_ClassDecl => { | |
| // We can find non-semantic children here, clang uses a | |
| // StructDecl to note incomplete structs that haven't been | |
| // forward-declared before, see [1]. | |
| // | |
| // Also, clang seems to scope struct definitions inside | |
| // unions, and other named struct definitions inside other | |
| // structs to the whole translation unit. | |
| // | |
| // Let's just assume that if the cursor we've found is a | |
| // definition, it's a valid inner type. | |
| // | |
| // [1]: https://github.com/rust-lang/rust-bindgen/issues/482 | |
| let is_inner_struct = | |
| cur.semantic_parent() == cursor || cur.is_definition(); | |
| if !is_inner_struct { | |
| return CXChildVisit_Continue; | |
| } | |
| // Even if this is a definition, we may not be the semantic | |
| // parent, see #1281. | |
| let inner = Item::parse(cur, Some(potential_id), ctx) | |
| .expect("Inner ClassDecl"); | |
| // 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); | |
| // A declaration of an union or a struct without name | |
| // could also be an unnamed field, unfortunately. | |
| if cur.is_anonymous() && 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)); | |
| } | |
| } | |
| } | |
| CXCursor_PackedAttr => { | |
| ci.packed_attr = true; | |
| } | |
| CXCursor_TemplateTypeParameter => { | |
| let param = Item::type_param(None, cur, ctx).expect( | |
| "Item::type_param shouldn't fail when pointing \ | |
| at a TemplateTypeParameter", | |
| ); | |
| ci.template_params.push(param); | |
| } | |
| CXCursor_CXXBaseSpecifier => { | |
| let is_virtual_base = cur.is_virtual_base(); | |
| ci.has_own_virtual_method |= is_virtual_base; | |
| let kind = if is_virtual_base { | |
| BaseKind::Virtual | |
| } else { | |
| BaseKind::Normal | |
| }; | |
| let field_name = match ci.base_members.len() { | |
| 0 => "_base".into(), | |
| n => format!("_base_{n}"), | |
| }; | |
| let type_id = | |
| Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx); | |
| ci.base_members.push(Base { | |
| ty: type_id, | |
| kind, | |
| field_name, | |
| is_pub: cur.access_specifier() == CX_CXXPublic, | |
| }); | |
| } | |
| CXCursor_Constructor | CXCursor_Destructor | | |
| CXCursor_CXXMethod => { | |
| let is_virtual = cur.method_is_virtual(); | |
| let is_static = cur.method_is_static(); | |
| debug_assert!(!(is_static && is_virtual), "How?"); | |
| ci.has_destructor |= cur.kind() == CXCursor_Destructor; | |
| ci.has_own_virtual_method |= is_virtual; | |
| // This used to not be here, but then I tried generating | |
| // stylo bindings with this (without path filters), and | |
| // cried a lot with a method in gfx/Point.h | |
| // (ToUnknownPoint), that somehow was causing the same type | |
| // to be inserted in the map two times. | |
| // | |
| // I couldn't make a reduced test case, but anyway... | |
| // Methods of template functions not only used to be inlined, | |
| // but also instantiated, and we wouldn't be able to call | |
| // them, so just bail out. | |
| if !ci.template_params.is_empty() { | |
| return CXChildVisit_Continue; | |
| } | |
| // NB: This gets us an owned `Function`, not a | |
| // `FunctionSig`. | |
| let signature = | |
| match Item::parse(cur, Some(potential_id), ctx) { | |
| Ok(item) | |
| if ctx | |
| .resolve_item(item) | |
| .kind() | |
| .is_function() => | |
| { | |
| item | |
| } | |
| _ => return CXChildVisit_Continue, | |
| }; | |
| let signature = signature.expect_function_id(ctx); | |
| match cur.kind() { | |
| CXCursor_Constructor => { | |
| ci.constructors.push(signature); | |
| } | |
| CXCursor_Destructor => { | |
| let kind = if is_virtual { | |
| MethodKind::VirtualDestructor { | |
| pure_virtual: cur.method_is_pure_virtual(), | |
| } | |
| } else { | |
| MethodKind::Destructor | |
| }; | |
| ci.destructor = Some((kind, signature)); | |
| } | |
| CXCursor_CXXMethod => { | |
| let is_const = cur.method_is_const(); | |
| let method_kind = if is_static { | |
| MethodKind::Static | |
| } else if is_virtual { | |
| MethodKind::Virtual { | |
| pure_virtual: cur.method_is_pure_virtual(), | |
| } | |
| } else if cur.method_is_explicit_object() { | |
| MethodKind::ExplicitObject | |
| } else { | |
| MethodKind::Normal | |
| }; | |
| let method = | |
| Method::new(method_kind, signature, is_const); | |
| ci.methods.push(method); | |
| } | |
| _ => unreachable!("How can we see this here?"), | |
| } | |
| } | |
| CXCursor_NonTypeTemplateParameter => { | |
| ci.has_non_type_template_params = true; | |
| } | |
| CXCursor_VarDecl => { | |
| let linkage = cur.linkage(); | |
| if linkage != CXLinkage_External && | |
| linkage != CXLinkage_UniqueExternal | |
| { | |
| return CXChildVisit_Continue; | |
| } | |
| let visibility = cur.visibility(); | |
| if visibility != CXVisibility_Default { | |
| return CXChildVisit_Continue; | |
| } | |
| if let Ok(item) = Item::parse(cur, Some(potential_id), ctx) | |
| { | |
| ci.inner_vars.push(item.as_var_id_unchecked()); | |
| } | |
| } | |
| // Intentionally not handled | |
| CXCursor_CXXAccessSpecifier | | |
| CXCursor_CXXFinalAttr | | |
| CXCursor_FunctionTemplate | | |
| CXCursor_ConversionFunction => {} | |
| _ => { | |
| warn!( | |
| "unhandled comp member `{}` (kind {:?}) in `{}` ({})", | |
| cur.spelling(), | |
| clang::kind_to_str(cur.kind()), | |
| cursor.spelling(), | |
| cur.location() | |
| ); | |
| } | |
| } | |
| CXChildVisit_Continue | |
| }); | |
| if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field { | |
| let field = | |
| RawField::new(None, ty, None, None, None, public, offset); | |
| ci.fields.append_raw_field(field); | |
| } | |
| Ok(ci) | |
| } | |
| fn kind_from_cursor( | |
| cursor: &clang::Cursor, | |
| ) -> Result<CompKind, ParseError> { | |
| use clang_sys::*; | |
| Ok(match cursor.kind() { | |
| CXCursor_UnionDecl => CompKind::Union, | |
| CXCursor_ClassDecl | CXCursor_StructDecl => CompKind::Struct, | |
| CXCursor_CXXBaseSpecifier | | |
| CXCursor_ClassTemplatePartialSpecialization | | |
| CXCursor_ClassTemplate => match cursor.template_kind() { | |
| CXCursor_UnionDecl => CompKind::Union, | |
| _ => CompKind::Struct, | |
| }, | |
| _ => { | |
| warn!("Unknown kind for comp type: {cursor:?}"); | |
| return Err(ParseError::Continue); | |
| } | |
| }) | |
| } | |
| /// Get the set of types that were declared within this compound type | |
| /// (e.g. nested class definitions). | |
| pub(crate) fn inner_types(&self) -> &[TypeId] { | |
| &self.inner_types | |
| } | |
| /// Get the set of static variables declared within this compound type. | |
| pub(crate) fn inner_vars(&self) -> &[VarId] { | |
| &self.inner_vars | |
| } | |
| /// Have we found a field with an opaque type that could potentially mess up | |
| /// the layout of this compound type? | |
| pub(crate) fn found_unknown_attr(&self) -> bool { | |
| self.found_unknown_attr | |
| } | |
| /// Is this compound type packed? | |
| pub(crate) fn is_packed( | |
| &self, | |
| ctx: &BindgenContext, | |
| layout: Option<&Layout>, | |
| ) -> bool { | |
| if self.packed_attr { | |
| return true; | |
| } | |
| // Even though `libclang` doesn't expose `#pragma packed(...)`, we can | |
| // detect it through its effects. | |
| if let Some(parent_layout) = layout { | |
| 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; | |
| } | |
| if self.has_own_virtual_method && parent_layout.align == 1 { | |
| return true; | |
| } | |
| } | |
| false | |
| } | |
| /// Return true if a compound type is "naturally packed". This means we can exclude the | |
| /// "packed" attribute without changing the layout. | |
| /// This is useful for types that need an "align(N)" attribute since rustc won't compile | |
| /// structs that have both of those attributes. | |
| pub(crate) fn already_packed(&self, ctx: &BindgenContext) -> Option<bool> { | |
| let mut total_size: usize = 0; | |
| for field in self.fields() { | |
| let layout = field.layout(ctx)?; | |
| if layout.align != 0 && total_size % layout.align != 0 { | |
| return Some(false); | |
| } | |
| total_size += layout.size; | |
| } | |
| Some(true) | |
| } | |
| /// Returns true if compound type has been forward declared | |
| pub(crate) fn is_forward_declaration(&self) -> bool { | |
| self.is_forward_declaration | |
| } | |
| /// Compute this compound structure's bitfield allocation units. | |
| pub(crate) 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. | |
| pub(crate) fn assign_field_names( | |
| &mut self, | |
| ctx: &BindgenContext, | |
| canonical_type_name: &str, | |
| ) { | |
| self.fields | |
| .assign_field_names(ctx, canonical_type_name, &self.methods); | |
| } | |
| /// Returns whether the current union can be represented as a Rust `union` | |
| /// | |
| /// Requirements: | |
| /// 1. Current `RustTarget` allows for `untagged_union` | |
| /// 2. Each field can derive `Copy` or we use `ManuallyDrop`. | |
| /// 3. It's not zero-sized. | |
| /// | |
| /// Second boolean returns whether all fields can be copied (and thus | |
| /// `ManuallyDrop` is not needed). | |
| pub(crate) fn is_rust_union( | |
| &self, | |
| ctx: &BindgenContext, | |
| layout: Option<&Layout>, | |
| name: &str, | |
| ) -> (bool, bool) { | |
| if !self.is_union() { | |
| return (false, false); | |
| } | |
| if !ctx.options().untagged_union { | |
| return (false, false); | |
| } | |
| if self.is_forward_declaration() { | |
| return (false, false); | |
| } | |
| let union_style = if ctx.options().bindgen_wrapper_union.matches(name) { | |
| NonCopyUnionStyle::BindgenWrapper | |
| } else if ctx.options().manually_drop_union.matches(name) { | |
| NonCopyUnionStyle::ManuallyDrop | |
| } else { | |
| ctx.options().default_non_copy_union_style | |
| }; | |
| let all_can_copy = self.fields().iter().all(|f| match *f { | |
| Field::DataMember(ref field_data) => { | |
| field_data.ty().can_derive_copy(ctx) | |
| } | |
| Field::Bitfields(_) => true, | |
| }); | |
| if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper { | |
| return (false, false); | |
| } | |
| if layout.is_some_and(|l| l.size == 0) && | |
| union_style != NonCopyUnionStyle::ManuallyDrop | |
| { | |
| return (false, false); | |
| } | |
| (true, all_can_copy) | |
| } | |
| } | |
| impl DotAttributes for CompInfo { | |
| fn dot_attributes<W>( | |
| &self, | |
| ctx: &BindgenContext, | |
| out: &mut W, | |
| ) -> io::Result<()> | |
| where | |
| W: io::Write, | |
| { | |
| writeln!(out, "<tr><td>CompKind</td><td>{:?}</td></tr>", self.kind)?; | |
| if self.has_own_virtual_method { | |
| writeln!(out, "<tr><td>has_vtable</td><td>true</td></tr>")?; | |
| } | |
| if self.has_destructor { | |
| writeln!(out, "<tr><td>has_destructor</td><td>true</td></tr>")?; | |
| } | |
| if self.has_nonempty_base { | |
| writeln!(out, "<tr><td>has_nonempty_base</td><td>true</td></tr>")?; | |
| } | |
| if self.has_non_type_template_params { | |
| writeln!( | |
| out, | |
| "<tr><td>has_non_type_template_params</td><td>true</td></tr>" | |
| )?; | |
| } | |
| if self.packed_attr { | |
| writeln!(out, "<tr><td>packed_attr</td><td>true</td></tr>")?; | |
| } | |
| if self.is_forward_declaration { | |
| writeln!( | |
| out, | |
| "<tr><td>is_forward_declaration</td><td>true</td></tr>" | |
| )?; | |
| } | |
| if !self.fields().is_empty() { | |
| writeln!(out, r#"<tr><td>fields</td><td><table border="0">"#)?; | |
| for field in self.fields() { | |
| field.dot_attributes(ctx, out)?; | |
| } | |
| writeln!(out, "</table></td></tr>")?; | |
| } | |
| Ok(()) | |
| } | |
| } | |
| impl IsOpaque for CompInfo { | |
| type Extra = Option<Layout>; | |
| fn is_opaque( | |
| &self, | |
| ctx: &BindgenContext, | |
| _layout: &Option<Layout>, | |
| ) -> bool { | |
| if self.has_non_type_template_params || | |
| self.has_unevaluable_bit_field_width | |
| { | |
| return true; | |
| } | |
| // When we do not have the layout for a bitfield's type (for example, it | |
| // 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::Error = self.fields { | |
| return true; | |
| } | |
| // Bitfields with a width that is larger than their unit's width have | |
| // some strange things going on, and the best we can do is make the | |
| // whole struct opaque. | |
| if self.fields().iter().any(|f| match *f { | |
| Field::DataMember(_) => false, | |
| Field::Bitfields(ref unit) => unit.bitfields().iter().any(|bf| { | |
| let bitfield_layout = ctx | |
| .resolve_type(bf.ty()) | |
| .layout(ctx) | |
| .expect("Bitfield without layout? Gah!"); | |
| bf.width() / 8 > bitfield_layout.size as u32 | |
| }), | |
| }) { | |
| return true; | |
| } | |
| false | |
| } | |
| } | |
| impl TemplateParameters for CompInfo { | |
| fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> { | |
| self.template_params.clone() | |
| } | |
| } | |
| impl Trace for CompInfo { | |
| type Extra = Item; | |
| fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item) | |
| where | |
| T: Tracer, | |
| { | |
| for p in item.all_template_params(context) { | |
| tracer.visit_kind(p.into(), EdgeKind::TemplateParameterDefinition); | |
| } | |
| for ty in self.inner_types() { | |
| tracer.visit_kind(ty.into(), EdgeKind::InnerType); | |
| } | |
| for &var in self.inner_vars() { | |
| tracer.visit_kind(var.into(), EdgeKind::InnerVar); | |
| } | |
| for method in self.methods() { | |
| tracer.visit_kind(method.signature.into(), EdgeKind::Method); | |
| } | |
| if let Some((_kind, signature)) = self.destructor() { | |
| tracer.visit_kind(signature.into(), EdgeKind::Destructor); | |
| } | |
| for ctor in self.constructors() { | |
| tracer.visit_kind(ctor.into(), EdgeKind::Constructor); | |
| } | |
| // Base members and fields are not generated for opaque types (but all | |
| // of the above things are) so stop here. | |
| if item.is_opaque(context, &()) { | |
| return; | |
| } | |
| for base in self.base_members() { | |
| tracer.visit_kind(base.ty.into(), EdgeKind::BaseMember); | |
| } | |
| self.fields.trace(context, tracer, &()); | |
| } | |
| } |