blob: ce6ec25d1450795caec2f80bd4786a42370370d7 [file] [log] [blame]
//! Compound types (unions and structs) in our intermediate representation.
use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::{TemplateDeclaration, Type};
use clang;
use parse::{ClangItemParser, ParseError};
use std::cell::Cell;
/// 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,
/// The offset of the field (in bits)
offset: Option<usize>,
}
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,
offset: Option<usize>)
-> Field {
Field {
name: name,
ty: ty,
comment: comment,
annotations: annotations.unwrap_or_default(),
bitfield: bitfield,
mutable: mutable,
offset: offset,
}
}
/// 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
}
/// The offset of the field (in bits)
pub fn offset(&self) -> Option<usize> {
self.offset
}
}
impl CanDeriveDebug for Field {
type Extra = ();
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
self.ty.can_derive_debug(ctx, ())
}
}
impl CanDeriveDefault for Field {
type Extra = ();
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
self.ty.can_derive_default(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,
/// 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 can_derive_default cycle while cycling
/// around the template arguments.
detect_derive_default_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>,
/// 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: 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,
found_unknown_attr: false,
detect_derive_debug_cycle: Cell::new(false),
detect_derive_default_cycle: Cell::new(false),
detect_has_destructor_cycle: Cell::new(false),
is_forward_declaration: 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_forward_declaration =
location.map_or(true, |cur| match cur.kind() {
CXCursor_StructDecl |
CXCursor_UnionDecl |
CXCursor_ClassDecl => !cur.is_definition(),
_ => false,
});
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, _, offset)) =
maybe_anonymous_struct_field.take() {
let field =
Field::new(None, ty, None, None, None, false, offset);
ci.fields.push(field);
}
}
match cur.kind() {
CXCursor_FieldDecl => {
if let Some((ty, clang_ty, 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 = Field::new(None,
ty,
None,
None,
None,
false,
offset);
ci.fields.push(field);
}
}
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();
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 = Field::new(name,
field_type,
comment,
annotations,
bit_width,
is_mutable,
offset);
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 => {
// We can find non-semantic children here, clang uses a
// StructDecl to note incomplete structs that hasn't been
// forward-declared before, see:
//
// https://github.com/servo/rust-bindgen/issues/482
if cur.semantic_parent() != cursor {
return CXChildVisit_Continue;
}
let inner = Item::parse(cur, Some(potential_id), ctx)
.expect("Inner ClassDecl");
ci.inner_types.push(inner);
// A declaration of an union or a struct without name could
// also be an unnamed field, unfortunately.
if cur.spelling().is_empty() &&
cur.kind() != CXCursor_EnumDecl {
let ty = cur.cur_type();
let offset = cur.offset_of_field().ok();
maybe_anonymous_struct_field =
Some((inner, ty, offset));
}
}
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, _, offset)) = maybe_anonymous_struct_field {
let field = Field::new(None, ty, None, None, None, false, offset);
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))
})
}
/// Returns true if compound type has been forward declared
pub fn is_forward_declaration(&self) -> bool {
self.is_forward_declaration
}
}
impl TemplateDeclaration for CompInfo {
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
if self.template_args.is_empty() {
None
} else {
Some(self.template_args.clone())
}
}
}
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 CanDeriveDefault for CompInfo {
type Extra = Option<Layout>;
fn can_derive_default(&self,
ctx: &BindgenContext,
layout: Option<Layout>)
-> bool {
// We can reach here recursively via template parameters of a member,
// for example.
if self.detect_derive_default_cycle.get() {
warn!("Derive default 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_default_cycle.set(true);
let can_derive_default = !self.has_vtable(ctx) &&
!self.needs_explicit_vtable(ctx) &&
self.base_members
.iter()
.all(|base| base.ty.can_derive_default(ctx, ())) &&
self.template_args
.iter()
.all(|id| id.can_derive_default(ctx, ())) &&
self.fields
.iter()
.all(|f| f.can_derive_default(ctx, ())) &&
self.ref_template
.map_or(true, |id| id.can_derive_default(ctx, ()));
self.detect_derive_default_cycle.set(false);
can_derive_default
}
}
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 Trace for CompInfo {
type Extra = Item;
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
where T: Tracer,
{
// TODO: We should properly distinguish template instantiations from
// template declarations at the type level. Why are some template
// instantiations represented here instead of as
// TypeKind::TemplateInstantiation?
if let Some(template) = self.specialized_template() {
// This is an instantiation of a template declaration with concrete
// template type arguments.
tracer.visit(template);
let args = item.applicable_template_args(context);
for a in args {
tracer.visit(a);
}
} else {
let params = item.applicable_template_args(context);
// This is a template declaration with abstract template type
// parameters.
for p in params {
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
}
}
for base in self.base_members() {
tracer.visit(base.ty);
}
for field in self.fields() {
tracer.visit(field.ty());
}
for &ty in self.inner_types() {
tracer.visit(ty);
}
for &var in self.inner_vars() {
tracer.visit(var);
}
for method in self.methods() {
tracer.visit(method.signature);
}
for &ctor in self.constructors() {
tracer.visit(ctor);
}
}
}