summaryrefslogtreecommitdiff
path: root/src/ir/comp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/comp.rs')
-rw-r--r--src/ir/comp.rs962
1 files changed, 962 insertions, 0 deletions
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
new file mode 100644
index 00000000..968bf879
--- /dev/null
+++ b/src/ir/comp.rs
@@ -0,0 +1,962 @@
+//! Compound types (unions and structs) in our intermediate representation.
+
+use clang;
+use parse::{ClangItemParser, ParseError};
+use std::cell::Cell;
+use super::annotations::Annotations;
+use super::context::{BindgenContext, ItemId};
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::item::Item;
+use super::layout::Layout;
+use super::ty::Type;
+use super::type_collector::{ItemSet, TypeCollector};
+
+/// The kind of compound type.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum CompKind {
+ /// A struct.
+ Struct,
+ /// A union.
+ Union,
+}
+
+/// The kind of C++ method.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum MethodKind {
+ /// A constructor. We represent it as method for convenience, to avoid code
+ /// duplication.
+ Constructor,
+ /// A static method.
+ Static,
+ /// A normal method.
+ Normal,
+ /// A virtual method.
+ Virtual,
+}
+
+/// 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: ItemId,
+ is_const: bool,
+}
+
+impl Method {
+ /// Construct a new `Method`.
+ pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ Method {
+ kind: kind,
+ signature: signature,
+ is_const: 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 {
+ self.kind == MethodKind::Virtual
+ }
+
+ /// Is this a static method?
+ pub fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ /// Get the `ItemId` for the `Function` signature for this method.
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+
+ /// Is this a const qualified method?
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+}
+
+/// A struct representing a C++ field.
+#[derive(Clone, Debug)]
+pub struct Field {
+ /// The name of the field, empty if it's an unnamed bitfield width.
+ name: Option<String>,
+ /// The inner type.
+ ty: ItemId,
+ /// 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: Option<u32>,
+ /// If the C++ field is marked as `mutable`
+ mutable: bool,
+}
+
+impl Field {
+ /// Construct a new `Field`.
+ pub fn new(name: Option<String>,
+ ty: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ bitfield: Option<u32>,
+ mutable: bool)
+ -> Field {
+ Field {
+ name: name,
+ ty: ty,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ bitfield: bitfield,
+ mutable: mutable,
+ }
+ }
+
+ /// Get the name of this field.
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ /// Get the type of this field.
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ /// Get the comment for this field.
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ /// If this is a bitfield, how many bits does it need?
+ pub fn bitfield(&self) -> Option<u32> {
+ self.bitfield
+ }
+
+ /// Is this field marked as `mutable`?
+ pub fn is_mutable(&self) -> bool {
+ self.mutable
+ }
+
+ /// Get the annotations for this field.
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+}
+
+impl CanDeriveDebug for Field {
+ type Extra = ();
+
+ fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_debug(ctx, ())
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for Field {
+ type Extra = ();
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_copy(ctx, ())
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_copy_in_array(ctx, ())
+ }
+}
+
+
+/// 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: ItemId,
+ /// The kind of inheritance we're doing.
+ pub kind: BaseKind,
+}
+
+impl Base {
+ /// Whether this base class is inheriting virtually.
+ pub fn is_virtual(&self) -> bool {
+ self.kind == BaseKind::Virtual
+ }
+}
+
+/// 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: Vec<Field>,
+
+ /// The template parameters of this class. These are non-concrete, and
+ /// should always be a Type(TypeKind::Named(name)), but still they need to
+ /// be registered with an unique type id in the context.
+ template_args: Vec<ItemId>,
+
+ /// The method declarations inside this class, if in C++ mode.
+ methods: Vec<Method>,
+
+ /// The different constructors this struct or class contains.
+ constructors: Vec<ItemId>,
+
+ /// Vector of classes this one inherits from.
+ base_members: Vec<Base>,
+
+ /// The parent reference template if any.
+ ref_template: Option<ItemId>,
+
+ /// 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<ItemId>,
+
+ /// Set of static constants declared inside this class.
+ inner_vars: Vec<ItemId>,
+
+ /// Whether this type should generate an vtable (TODO: Should be able to
+ /// look at the virtual methods and ditch this field).
+ has_vtable: 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 struct layout is packed.
+ packed: bool,
+
+ /// Whether this struct is anonymous.
+ is_anonymous: 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 detect if we've run in a can_derive_debug cycle while cycling
+ /// around the template arguments.
+ detect_derive_debug_cycle: Cell<bool>,
+
+ /// Used to detect if we've run in a has_destructor cycle while cycling
+ /// around the template arguments.
+ detect_has_destructor_cycle: Cell<bool>,
+}
+
+impl CompInfo {
+ /// Construct a new compound type.
+ pub fn new(kind: CompKind) -> Self {
+ CompInfo {
+ kind: kind,
+ fields: vec![],
+ template_args: vec![],
+ methods: vec![],
+ constructors: vec![],
+ base_members: vec![],
+ ref_template: None,
+ inner_types: vec![],
+ inner_vars: vec![],
+ has_vtable: false,
+ has_destructor: false,
+ has_nonempty_base: false,
+ has_non_type_template_params: false,
+ packed: false,
+ is_anonymous: false,
+ found_unknown_attr: false,
+ detect_derive_debug_cycle: Cell::new(false),
+ detect_has_destructor_cycle: Cell::new(false),
+ }
+ }
+
+ /// Is this compound type unsized?
+ pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
+ !self.has_vtable(ctx) && self.fields.is_empty() &&
+ self.base_members.iter().all(|base| {
+ ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
+ }) &&
+ self.ref_template
+ .map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
+ }
+
+ /// Does this compound type have a destructor?
+ pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
+ if self.detect_has_destructor_cycle.get() {
+ warn!("Cycle detected looking for destructors");
+ // Assume no destructor, since we don't have an explicit one.
+ return false;
+ }
+
+ self.detect_has_destructor_cycle.set(true);
+
+ let has_destructor = self.has_destructor ||
+ match self.kind {
+ CompKind::Union => false,
+ CompKind::Struct => {
+ // NB: We can't rely on a type with type parameters
+ // not having destructor.
+ //
+ // This is unfortunate, but...
+ self.ref_template.as_ref().map_or(false, |t| {
+ ctx.resolve_type(*t).has_destructor(ctx)
+ }) ||
+ self.template_args.iter().any(|t| {
+ ctx.resolve_type(*t).has_destructor(ctx)
+ }) ||
+ self.base_members.iter().any(|base| {
+ ctx.resolve_type(base.ty).has_destructor(ctx)
+ }) ||
+ self.fields.iter().any(|field| {
+ ctx.resolve_type(field.ty)
+ .has_destructor(ctx)
+ })
+ }
+ };
+
+ self.detect_has_destructor_cycle.set(false);
+
+ has_destructor
+ }
+
+ /// Is this type a template specialization?
+ pub fn is_template_specialization(&self) -> bool {
+ self.ref_template.is_some()
+ }
+
+ /// Get the template declaration this specialization is specializing.
+ pub fn specialized_template(&self) -> Option<ItemId> {
+ self.ref_template
+ }
+
+ /// 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> {
+ use std::cmp;
+
+ // We can't do better than clang here, sorry.
+ if self.kind == CompKind::Struct {
+ return None;
+ }
+
+ let mut max_size = 0;
+ let mut max_align = 0;
+ for field in &self.fields {
+ let field_layout = ctx.resolve_type(field.ty)
+ .layout(ctx);
+
+ if let Some(layout) = field_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] {
+ &self.fields
+ }
+
+ /// Get this type's set of free template arguments. Empty if this is not a
+ /// template.
+ pub fn template_args(&self) -> &[ItemId] {
+ &self.template_args
+ }
+
+ /// 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
+ }
+
+ /// Does this type have a virtual table?
+ pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.has_vtable ||
+ self.base_members().iter().any(|base| {
+ ctx.resolve_type(base.ty)
+ .has_vtable(ctx)
+ }) ||
+ self.ref_template.map_or(false, |template| {
+ ctx.resolve_type(template).has_vtable(ctx)
+ })
+ }
+
+ /// 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) -> &[ItemId] {
+ &self.constructors
+ }
+
+ /// What kind of compound type is this?
+ pub fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ /// 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::*;
+ // Sigh... For class templates we want the location, for
+ // specialisations, we want the declaration... So just try both.
+ //
+ // TODO: Yeah, this code reads really bad.
+ 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 = try!(kind);
+
+ debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
+
+ let mut ci = CompInfo::new(kind);
+ ci.is_anonymous = cursor.is_anonymous();
+ ci.template_args = match ty.template_args() {
+ // In forward declarations and not specializations,
+ // etc, they are in
+ // the ast, we'll meet them in
+ // CXCursor_TemplateTypeParameter
+ None => vec![],
+ Some(arg_types) => {
+ let num_arg_types = arg_types.len();
+ let mut specialization = true;
+
+ let args = arg_types.filter(|t| t.kind() != CXType_Invalid)
+ .filter_map(|t| {
+ if t.spelling().starts_with("type-parameter") {
+ specialization = false;
+ None
+ } else {
+ Some(Item::from_ty_or_ref(t, None, None, ctx))
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if specialization && args.len() != num_arg_types {
+ ci.has_non_type_template_params = true;
+ warn!("warning: Template parameter is not a type");
+ }
+
+ if specialization { args } else { vec![] }
+ }
+ };
+
+ ci.ref_template = cursor.specialized()
+ .and_then(|c| Item::parse(c, None, ctx).ok());
+
+ let mut maybe_anonymous_struct_field = None;
+ cursor.visit(|cur| {
+ if cur.kind() != CXCursor_FieldDecl {
+ if let Some((ty, _)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+ maybe_anonymous_struct_field = None;
+ }
+
+ match cur.kind() {
+ CXCursor_FieldDecl => {
+ match maybe_anonymous_struct_field.take() {
+ Some((ty, clang_ty)) => {
+ let mut used = false;
+ cur.visit(|child| {
+ if child.cur_type() == clang_ty {
+ used = true;
+ }
+ CXChildVisit_Continue
+ });
+ if !used {
+ let field = Field::new(None,
+ ty,
+ None,
+ None,
+ None,
+ false);
+ ci.fields.push(field);
+ }
+ }
+ None => {}
+ }
+
+ let bit_width = cur.bit_width();
+ let field_type = Item::from_ty_or_ref(cur.cur_type(),
+ Some(cur),
+ Some(potential_id),
+ ctx);
+
+ let comment = cur.raw_comment();
+ let annotations = Annotations::new(&cur);
+ let name = cur.spelling();
+ let is_mutable = cursor.is_mutable_field();
+
+ // 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 = Field::new(name,
+ field_type,
+ comment,
+ annotations,
+ bit_width,
+ is_mutable);
+ ci.fields.push(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_TypedefDecl |
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ let inner = Item::parse(cur, Some(potential_id), ctx)
+ .expect("Inner ClassDecl");
+ if !ci.inner_types.contains(&inner) {
+ ci.inner_types.push(inner);
+ }
+ // A declaration of an union or a struct without name could
+ // also be an unnamed field, unfortunately.
+ if cur.spelling().is_empty() &&
+ cur.kind() != CXCursor_EnumDecl {
+ let ty = cur.cur_type();
+ maybe_anonymous_struct_field = Some((inner, ty));
+ }
+ }
+ CXCursor_PackedAttr => {
+ ci.packed = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ // Yes! You can arrive here with an empty template parameter
+ // name! Awesome, isn't it?
+ //
+ // see tests/headers/empty_template_param_name.hpp
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let param =
+ Item::named_type(cur.spelling(), potential_id, ctx);
+ ci.template_args.push(param);
+ }
+ CXCursor_CXXBaseSpecifier => {
+ let is_virtual_base = cur.is_virtual_base();
+ ci.has_vtable |= is_virtual_base;
+
+ let kind = if is_virtual_base {
+ BaseKind::Virtual
+ } else {
+ BaseKind::Normal
+ };
+
+ let type_id = Item::from_ty_or_ref(cur.cur_type(),
+ Some(cur),
+ None,
+ ctx);
+ ci.base_members.push(Base {
+ ty: type_id,
+ kind: kind,
+ });
+ }
+ 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_vtable |= 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 use to be inlined,
+ // but also instantiated, and we wouldn't be able to call
+ // them, so just bail out.
+ if !ci.template_args.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,
+ };
+
+ match cur.kind() {
+ CXCursor_Constructor => {
+ ci.constructors.push(signature);
+ }
+ // TODO(emilio): Bind the destructor?
+ CXCursor_Destructor => {}
+ CXCursor_CXXMethod => {
+ let is_const = cur.method_is_const();
+ let method_kind = if is_static {
+ MethodKind::Static
+ } else if is_virtual {
+ MethodKind::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);
+ }
+ }
+ // Intentionally not handled
+ CXCursor_CXXAccessSpecifier |
+ CXCursor_CXXFinalAttr |
+ CXCursor_FunctionTemplate |
+ CXCursor_ConversionFunction => {}
+ _ => {
+ warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
+ cur.spelling(),
+ cur.kind(),
+ cursor.spelling(),
+ cur.location());
+ }
+ }
+ CXChildVisit_Continue
+ });
+
+ if let Some((ty, _)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(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);
+ }
+ })
+ }
+
+ /// Do any of the types that participate in this type's "signature" use the
+ /// named type `ty`?
+ ///
+ /// See also documentation for `ir::Item::signature_contains_named_type`.
+ pub fn signature_contains_named_type(&self,
+ ctx: &BindgenContext,
+ ty: &Type)
+ -> bool {
+ // We don't generate these, so rather don't make the codegen step to
+ // think we got it covered.
+ if self.has_non_type_template_params() {
+ return false;
+ }
+ self.template_args.iter().any(|arg| {
+ ctx.resolve_type(*arg)
+ .signature_contains_named_type(ctx, ty)
+ })
+ }
+
+ /// Get the set of types that were declared within this compound type
+ /// (e.g. nested class definitions).
+ pub fn inner_types(&self) -> &[ItemId] {
+ &self.inner_types
+ }
+
+ /// Get the set of static variables declared within this compound type.
+ pub fn inner_vars(&self) -> &[ItemId] {
+ &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 packed(&self) -> bool {
+ self.packed
+ }
+
+ /// Returns whether this type needs an explicit vtable because it has
+ /// virtual methods and none of its base classes has already a vtable.
+ pub fn needs_explicit_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.has_vtable(ctx) &&
+ !self.base_members.iter().any(|base| {
+ // NB: Ideally, we could rely in all these types being `comp`, and
+ // life would be beautiful.
+ //
+ // Unfortunately, given the way we implement --match-pat, and also
+ // that you can inherit from templated types, we need to handle
+ // other cases here too.
+ ctx.resolve_type(base.ty)
+ .canonical_type(ctx)
+ .as_comp()
+ .map_or(false, |ci| ci.has_vtable(ctx))
+ })
+ }
+}
+
+impl CanDeriveDebug for CompInfo {
+ type Extra = Option<Layout>;
+
+ fn can_derive_debug(&self,
+ ctx: &BindgenContext,
+ layout: Option<Layout>)
+ -> bool {
+ if self.has_non_type_template_params() {
+ return layout.map_or(false, |l| l.opaque().can_derive_debug(ctx, ()));
+ }
+
+ // We can reach here recursively via template parameters of a member,
+ // for example.
+ if self.detect_derive_debug_cycle.get() {
+ warn!("Derive debug cycle detected!");
+ return true;
+ }
+
+ if self.kind == CompKind::Union {
+ if ctx.options().unstable_rust {
+ return false;
+ }
+
+ return layout.unwrap_or_else(Layout::zero)
+ .opaque()
+ .can_derive_debug(ctx, ());
+ }
+
+ self.detect_derive_debug_cycle.set(true);
+
+ let can_derive_debug = {
+ self.base_members
+ .iter()
+ .all(|base| base.ty.can_derive_debug(ctx, ())) &&
+ self.template_args
+ .iter()
+ .all(|id| id.can_derive_debug(ctx, ())) &&
+ self.fields
+ .iter()
+ .all(|f| f.can_derive_debug(ctx, ())) &&
+ self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
+ };
+
+ self.detect_derive_debug_cycle.set(false);
+
+ can_derive_debug
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for CompInfo {
+ type Extra = (&'a Item, Option<Layout>);
+
+ fn can_derive_copy(&self,
+ ctx: &BindgenContext,
+ (item, layout): (&Item, Option<Layout>))
+ -> bool {
+ if self.has_non_type_template_params() {
+ return layout.map_or(false, |l| l.opaque().can_derive_copy(ctx, ()));
+ }
+
+ // NOTE: Take into account that while unions in C and C++ are copied by
+ // default, the may have an explicit destructor in C++, so we can't
+ // defer this check just for the union case.
+ if self.has_destructor(ctx) {
+ return false;
+ }
+
+ if self.kind == CompKind::Union {
+ if !ctx.options().unstable_rust {
+ // NOTE: If there's no template parameters we can derive copy
+ // unconditionally, since arrays are magical for rustc, and
+ // __BindgenUnionField always implements copy.
+ return true;
+ }
+
+ // https://github.com/rust-lang/rust/issues/36640
+ if !self.template_args.is_empty() || self.ref_template.is_some() ||
+ !item.applicable_template_args(ctx).is_empty() {
+ return false;
+ }
+ }
+
+ // With template args, use a safe subset of the types,
+ // since copyability depends on the types itself.
+ self.ref_template
+ .as_ref()
+ .map_or(true, |t| t.can_derive_copy(ctx, ())) &&
+ self.base_members
+ .iter()
+ .all(|base| base.ty.can_derive_copy(ctx, ())) &&
+ self.fields.iter().all(|field| field.can_derive_copy(ctx, ()))
+ }
+
+ fn can_derive_copy_in_array(&self,
+ ctx: &BindgenContext,
+ extra: (&Item, Option<Layout>))
+ -> bool {
+ self.can_derive_copy(ctx, extra)
+ }
+}
+
+impl TypeCollector for CompInfo {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ if let Some(template) = self.specialized_template() {
+ types.insert(template);
+ }
+
+ let applicable_template_args = item.applicable_template_args(context);
+ for arg in applicable_template_args {
+ types.insert(arg);
+ }
+
+ for base in self.base_members() {
+ types.insert(base.ty);
+ }
+
+ for field in self.fields() {
+ types.insert(field.ty());
+ }
+
+ for &ty in self.inner_types() {
+ types.insert(ty);
+ }
+
+ for &var in self.inner_vars() {
+ types.insert(var);
+ }
+
+ // FIXME(emilio): Methods, VTable?
+ }
+}