//! 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; /// 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; } /// 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, } 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 { 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(&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( &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#" bitfield unit "#, layout.size, layout.align )?; for bf in bitfields { bf.dot_attributes(ctx, out)?; } writeln!(out, "
unit.size{}
unit.align{}
") } } } } impl DotAttributes for FieldData { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{}{:?}", self.name().unwrap_or("(anonymous)"), self.ty() ) } } impl DotAttributes for Bitfield { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{} : {}{:?}", 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, /// Name of the generated Rust setter for this bitfield. /// /// Should be assigned before codegen. setter_name: Option, } 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::() 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 { self.data.bitfield_width() } fn is_public(&self) -> bool { self.data.is_public() } fn annotations(&self) -> &Annotations { self.data.annotations() } fn offset(&self) -> Option { 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, ty: TypeId, comment: Option, annotations: Option, bitfield_width: Option, public: bool, offset: Option, ) -> 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 { self.0.bitfield_width() } fn is_public(&self) -> bool { self.0.is_public() } fn annotations(&self) -> &Annotations { self.0.annotations() } fn offset(&self) -> Option { 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( ctx: &BindgenContext, raw_fields: I, packed: bool, ) -> Result<(Vec, bool), ()> where I: IntoIterator, { 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( ctx: &BindgenContext, bitfield_unit_count: &mut usize, fields: &mut E, raw_bitfields: I, packed: bool, ) -> Result<(), ()> where E: Extend, I: IntoIterator, { 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( fields: &mut E, bitfield_unit_count: &mut usize, unit_size_in_bits: usize, unit_align_in_bits: usize, bitfields: Vec, packed: bool, ) where E: Extend, { *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), After { fields: Vec, 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 = 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(&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, /// The inner type. ty: TypeId, /// The doc comment on the field if any. comment: Option, /// 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, /// If the C++ field is declared `public` public: bool, /// The offset of the field (in bits) offset: Option, } 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 { self.bitfield_width } fn is_public(&self) -> bool { self.public } fn annotations(&self) -> &Annotations { &self.annotations } fn offset(&self) -> Option { 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, /// The method declarations inside this class, if in C++ mode. methods: Vec, /// The different constructors this struct or class contains. constructors: Vec, /// 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, /// 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, /// Set of static constants declared inside this class. inner_vars: Vec, /// 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 { // 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, ctx: &mut BindgenContext, ) -> Result { 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 { 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( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!(out, "CompKind{:?}", self.kind)?; if self.has_own_virtual_method { writeln!(out, "has_vtabletrue")?; } if self.has_destructor { writeln!(out, "has_destructortrue")?; } if self.has_nonempty_base { writeln!(out, "has_nonempty_basetrue")?; } if self.has_non_type_template_params { writeln!( out, "has_non_type_template_paramstrue" )?; } if self.packed_attr { writeln!(out, "packed_attrtrue")?; } if self.is_forward_declaration { writeln!( out, "is_forward_declarationtrue" )?; } if !self.fields().is_empty() { writeln!(out, r#"fields"#)?; for field in self.fields() { field.dot_attributes(ctx, out)?; } writeln!(out, "
")?; } Ok(()) } } impl IsOpaque for CompInfo { type Extra = Option; fn is_opaque(&self, ctx: &BindgenContext, layout: &Option) -> 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 { self.template_params.clone() } } impl Trace for CompInfo { type Extra = Item; fn trace(&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, &()); } }