summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/ir/comp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/ir/comp.rs')
-rw-r--r--third_party/rust/bindgen/ir/comp.rs1890
1 files changed, 1890 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/ir/comp.rs b/third_party/rust/bindgen/ir/comp.rs
new file mode 100644
index 0000000000..18a4291cf9
--- /dev/null
+++ b/third_party/rust/bindgen/ir/comp.rs
@@ -0,0 +1,1890 @@
+//! 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::clang;
+use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2};
+use crate::ir::derive::CanDeriveCopy;
+use crate::parse::ParseError;
+use crate::HashMap;
+use crate::NonCopyUnionStyle;
+use peeking_take_while::PeekableExt;
+use std::cmp;
+use std::io;
+use std::mem;
+
+/// The kind of compound type.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum CompKind {
+ /// A struct.
+ Struct,
+ /// A union.
+ Union,
+}
+
+/// The kind of C++ method.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub 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 normal method.
+ Normal,
+ /// A virtual method.
+ Virtual {
+ /// Whether it's pure virtual.
+ pure_virtual: bool,
+ },
+}
+
+impl MethodKind {
+ /// Is this a destructor method?
+ pub fn is_destructor(&self) -> bool {
+ matches!(
+ *self,
+ MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
+ )
+ }
+
+ /// Is this a pure virtual method?
+ pub 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, either static, normal, or virtual.
+#[derive(Debug)]
+pub 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 fn new(
+ kind: MethodKind,
+ signature: FunctionId,
+ is_const: bool,
+ ) -> Self {
+ Method {
+ kind,
+ signature,
+ is_const,
+ }
+ }
+
+ /// What kind of method is this?
+ pub fn kind(&self) -> MethodKind {
+ self.kind
+ }
+
+ /// Is this a constructor?
+ pub fn is_constructor(&self) -> bool {
+ self.kind == MethodKind::Constructor
+ }
+
+ /// Is this a virtual method?
+ pub fn is_virtual(&self) -> bool {
+ matches!(
+ self.kind,
+ MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
+ )
+ }
+
+ /// Is this a static method?
+ pub fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ /// Get the id for the `Function` signature for this method.
+ pub fn signature(&self) -> FunctionId {
+ self.signature
+ }
+
+ /// Is this a const qualified method?
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+}
+
+/// Methods common to the various field types.
+pub 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.
+ fn comment(&self) -> Option<&str>;
+
+ /// If this is a bitfield, how many bits does it need?
+ fn bitfield_width(&self) -> Option<u32>;
+
+ /// Is this feild 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 struct BitfieldUnit {
+ nth: usize,
+ layout: Layout,
+ 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 fn nth(&self) -> usize {
+ self.nth
+ }
+
+ /// Get the layout within which these bitfields reside.
+ pub fn layout(&self) -> Layout {
+ self.layout
+ }
+
+ /// Get the bitfields within this unit.
+ pub fn bitfields(&self) -> &[Bitfield] {
+ &self.bitfields
+ }
+}
+
+/// A struct representing a C++ field.
+#[derive(Debug)]
+pub 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 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 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 fn offset_into_unit(&self) -> usize {
+ self.offset_into_unit
+ }
+
+ /// Get the mask value that when &'ed with this bitfield's allocation unit
+ /// produces this bitfield's value.
+ pub fn mask(&self) -> u64 {
+ use std::u64;
+
+ let unoffseted_mask =
+ if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
+ u64::MAX
+ } else {
+ (1u64 << self.width()) - 1u64
+ };
+
+ unoffseted_mask << self.offset_into_unit()
+ }
+
+ /// Get the bit width of this bitfield.
+ pub 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 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 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. We introduce a scope here so that we can use
+ // `raw_fields` again after the `by_ref` iterator adaptor is dropped.
+ {
+ let non_bitfields = raw_fields
+ .by_ref()
+ .peeking_take_while(|f| f.bitfield_width().is_none())
+ .map(|f| Field::DataMember(f.0));
+ fields.extend(non_bitfields);
+ }
+
+ // Now gather all the consecutive bitfields. Only consecutive bitfields
+ // may potentially share a bitfield allocation unit with each other in
+ // the Itanium C++ ABI.
+ let mut bitfields = raw_fields
+ .by_ref()
+ .peeking_take_while(|f| f.bitfield_width().is_some())
+ .peekable();
+
+ if bitfields.peek().is_none() {
+ 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,
+ unit_align_in_bits: usize,
+ bitfields: Vec<Bitfield>,
+ packed: bool,
+ ) where
+ E: Extend<Field>,
+ {
+ *bitfield_unit_count += 1;
+ let align = if packed {
+ 1
+ } else {
+ bytes_from_bits_pow2(unit_align_in_bits)
+ };
+ 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,
+ bitfields,
+ })));
+ }
+
+ let mut max_align = 0;
+ let mut unfilled_bits_in_unit = 0;
+ let mut unit_size_in_bits = 0;
+ let mut unit_align = 0;
+ let mut bitfields_in_unit = vec![];
+
+ // TODO(emilio): Determine this from attributes or pragma ms_struct
+ // directives. Also, perhaps we should check if the target is MSVC?
+ const is_ms_struct: bool = false;
+
+ 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_size = bitfield_layout.size;
+ let bitfield_align = bitfield_layout.align;
+
+ let mut offset = unit_size_in_bits;
+ if !packed {
+ if is_ms_struct {
+ if unit_size_in_bits != 0 &&
+ (bitfield_width == 0 ||
+ bitfield_width > unfilled_bits_in_unit)
+ {
+ // We've reached the end of this allocation unit, so flush it
+ // and its bitfields.
+ unit_size_in_bits =
+ align_to(unit_size_in_bits, unit_align * 8);
+ flush_allocation_unit(
+ fields,
+ bitfield_unit_count,
+ unit_size_in_bits,
+ unit_align,
+ mem::take(&mut bitfields_in_unit),
+ packed,
+ );
+
+ // Now we're working on a fresh bitfield allocation unit, so reset
+ // the current unit size and alignment.
+ 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);
+ }
+ }
+
+ // 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);
+
+ // NB: The `bitfield_width` here is completely, absolutely
+ // intentional. Alignment of the allocation unit is based on the
+ // maximum bitfield width, not (directly) on the bitfields' types'
+ // alignment.
+ unit_align = cmp::max(unit_align, bitfield_width);
+ }
+
+ // 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
+ bitfields_in_unit.push(Bitfield::new(offset, bitfield));
+
+ unit_size_in_bits = offset + bitfield_width;
+
+ // Compute what the physical unit's final size would be given what we
+ // have seen so far, and use that to compute how many bits are still
+ // available in the unit.
+ let data_size = align_to(unit_size_in_bits, bitfield_align * 8);
+ unfilled_bits_in_unit = data_size - unit_size_in_bits;
+ }
+
+ 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,
+ unit_align,
+ bitfields_in_unit,
+ packed,
+ );
+ }
+
+ 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 deanonymize_fields(&mut self, ctx: &BindgenContext, 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.");
+ }
+ };
+
+ 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!(
+ "{}{}",
+ ctx.options().anon_fields_prefix,
+ anon_field_counter
+ ));
+ }
+ 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);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+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 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
+ }
+}
+
+/// The kind of inheritance a base class is using.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub 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 struct Base {
+ /// The type of this base class.
+ pub ty: TypeId,
+ /// The kind of inheritance we're doing.
+ pub kind: BaseKind,
+ /// Name of the field in which this base should be stored.
+ pub field_name: String,
+ /// Whether this base is inherited from publically.
+ pub is_pub: bool,
+}
+
+impl Base {
+ /// Whether this base class is inheriting virtually.
+ pub fn is_virtual(&self) -> bool {
+ self.kind == BaseKind::Virtual
+ }
+
+ /// Whether this base class should have it's own field for storage.
+ pub 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 publically.
+ pub 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 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:
+ ///
+ /// 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 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 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 fn fields(&self) -> &[Field] {
+ match self.fields {
+ 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::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 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 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 fn has_own_virtual_method(&self) -> bool {
+ self.has_own_virtual_method
+ }
+
+ /// Did we see a destructor when parsing this type?
+ pub fn has_own_destructor(&self) -> bool {
+ self.has_destructor
+ }
+
+ /// Get this type's set of methods.
+ pub fn methods(&self) -> &[Method] {
+ &self.methods
+ }
+
+ /// Get this type's set of constructors.
+ pub fn constructors(&self) -> &[FunctionId] {
+ &self.constructors
+ }
+
+ /// Get this type's destructor.
+ pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
+ self.destructor
+ }
+
+ /// What kind of compound type is this?
+ pub fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ /// Is this a union?
+ pub fn is_union(&self) -> bool {
+ self.kind() == CompKind::Union
+ }
+
+ /// The set of types that this one inherits from.
+ pub fn base_members(&self) -> &[Base] {
+ &self.base_members
+ }
+
+ /// Construct a new compound type from a Clang type.
+ pub 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 should'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() ==
+ clang_sys::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 {
+ 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 fn inner_types(&self) -> &[TypeId] {
+ &self.inner_types
+ }
+
+ /// Get the set of static variables declared within this compound type.
+ pub 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 fn found_unknown_attr(&self) -> bool {
+ self.found_unknown_attr
+ }
+
+ /// Is this compound type packed?
+ pub 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
+ }
+
+ /// Returns true if compound type has been forward declared
+ pub fn is_forward_declaration(&self) -> bool {
+ self.is_forward_declaration
+ }
+
+ /// Compute this compound structure's bitfield allocation units.
+ 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.
+ pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) {
+ self.fields.deanonymize_fields(ctx, &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 fn is_rust_union(
+ &self,
+ ctx: &BindgenContext,
+ layout: Option<&Layout>,
+ name: &str,
+ ) -> (bool, bool) {
+ if !self.is_union() {
+ return (false, false);
+ }
+
+ if !ctx.options().rust_features().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.map_or(false, |l| l.size == 0) {
+ 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;
+ }
+
+ if !ctx.options().rust_features().repr_packed_n {
+ // If we don't have `#[repr(packed(N)]`, the best we can
+ // do is make this struct opaque.
+ //
+ // See https://github.com/rust-lang/rust-bindgen/issues/537 and
+ // https://github.com/rust-lang/rust/issues/33158
+ if self.is_packed(ctx, layout.as_ref()) &&
+ layout.map_or(false, |l| l.align > 1)
+ {
+ warn!("Found a type that is both packed and aligned to greater than \
+ 1; Rust before version 1.33 doesn't have `#[repr(packed(N))]`, so we \
+ are treating it as opaque. You may wish to set bindgen's rust target \
+ version to 1.33 or later to enable `#[repr(packed(N))]` support.");
+ 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, &());
+ }
+}