use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDefault};
use super::dot::DotAttributes;
use super::item::{IsOpaque, Item};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use super::template::TemplateParameters;
use clang;
use codegen::struct_layout::{align_to, bytes_from_bits_pow2};
use parse::{ClangItemParser, ParseError};
use peeking_take_while::PeekableExt;
use std::cell::Cell;
use std::cmp;
use std::io;
use std::mem;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CompKind {
Struct,
Union,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MethodKind {
Constructor,
Destructor,
VirtualDestructor,
Static,
Normal,
Virtual,
}
#[derive(Debug)]
pub struct Method {
kind: MethodKind,
signature: ItemId,
is_const: bool,
}
impl Method {
pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
Method {
kind: kind,
signature: signature,
is_const: is_const,
}
}
pub fn kind(&self) -> MethodKind {
self.kind
}
pub fn is_destructor(&self) -> bool {
self.kind == MethodKind::Destructor ||
self.kind == MethodKind::VirtualDestructor
}
pub fn is_constructor(&self) -> bool {
self.kind == MethodKind::Constructor
}
pub fn is_virtual(&self) -> bool {
self.kind == MethodKind::Virtual ||
self.kind == MethodKind::VirtualDestructor
}
pub fn is_static(&self) -> bool {
self.kind == MethodKind::Static
}
pub fn signature(&self) -> ItemId {
self.signature
}
pub fn is_const(&self) -> bool {
self.is_const
}
}
pub trait FieldMethods {
fn name(&self) -> Option<&str>;
fn ty(&self) -> ItemId;
fn comment(&self) -> Option<&str>;
fn bitfield(&self) -> Option<u32>;
fn is_mutable(&self) -> bool;
fn annotations(&self) -> &Annotations;
fn offset(&self) -> Option<usize>;
}
#[derive(Debug)]
pub struct BitfieldUnit {
nth: usize,
layout: Layout,
bitfields: Vec<Bitfield>,
}
impl BitfieldUnit {
pub fn nth(&self) -> usize {
self.nth
}
pub fn layout(&self) -> Layout {
self.layout
}
pub fn bitfields(&self) -> &[Bitfield] {
&self.bitfields
}
}
#[derive(Debug)]
pub enum Field {
DataMember(FieldData),
Bitfields(BitfieldUnit),
}
impl Field {
fn has_destructor(&self, ctx: &BindgenContext) -> bool {
match *self {
Field::DataMember(ref data) => ctx.resolve_type(data.ty).has_destructor(ctx),
Field::Bitfields(BitfieldUnit { .. }) => false,
}
}
pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
match *self {
Field::Bitfields(BitfieldUnit { layout, ..}) => Some(layout),
Field::DataMember(ref data) => {
ctx.resolve_type(data.ty).layout(ctx)
}
}
}
}
impl Trace for Field {
type Extra = ();
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
where T: Tracer,
{
match *self {
Field::DataMember(ref data) => {
tracer.visit_kind(data.ty, EdgeKind::Field);
}
Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => {
for bf in bitfields {
tracer.visit_kind(bf.ty(), EdgeKind::Field);
}
}
}
}
}
impl DotAttributes for Field {
fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
where W: io::Write
{
match *self {
Field::DataMember(ref data) => {
data.dot_attributes(ctx, out)
}
Field::Bitfields(BitfieldUnit { layout, ref bitfields, .. }) => {
writeln!(out,
r#"<tr>
<td>bitfield unit</td>
<td>
<table border="0">
<tr>
<td>unit.size</td><td>{}</td>
</tr>
<tr>
<td>unit.align</td><td>{}</td>
</tr>
"#,
layout.size,
layout.align)?;
for bf in bitfields {
bf.dot_attributes(ctx, out)?;
}
writeln!(out, "</table></td></tr>")
}
}
}
}
impl DotAttributes for FieldData {
fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
where W: io::Write
{
writeln!(out,
"<tr><td>{}</td><td>{:?}</td></tr>",
self.name().unwrap_or("(anonymous)"),
self.ty())
}
}
impl DotAttributes for Bitfield {
fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
where W: io::Write
{
writeln!(out,
"<tr><td>{} : {}</td><td>{:?}</td></tr>",
self.name(),
self.width(),
self.ty())
}
}
#[derive(Debug)]
pub struct Bitfield {
offset_into_unit: usize,
data: FieldData,
}
impl Bitfield {
fn new(offset_into_unit: usize, raw: RawField) -> Bitfield {
assert!(raw.bitfield().is_some());
assert!(raw.name().is_some());
Bitfield {
offset_into_unit: offset_into_unit,
data: raw.0,
}
}
pub fn offset_into_unit(&self) -> usize {
self.offset_into_unit
}
pub fn mask(&self) -> u64 {
use std::mem;
use std::u64;
let unoffseted_mask =
if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
u64::MAX
} else {
((1u64 << self.width()) - 1u64)
};
unoffseted_mask << self.offset_into_unit()
}
pub fn width(&self) -> u32 {
self.data.bitfield().unwrap()
}
pub fn name(&self) -> &str {
self.data.name().unwrap()
}
}
impl FieldMethods for Bitfield {
fn name(&self) -> Option<&str> {
self.data.name()
}
fn ty(&self) -> ItemId {
self.data.ty()
}
fn comment(&self) -> Option<&str> {
self.data.comment()
}
fn bitfield(&self) -> Option<u32> {
self.data.bitfield()
}
fn is_mutable(&self) -> bool {
self.data.is_mutable()
}
fn annotations(&self) -> &Annotations {
self.data.annotations()
}
fn offset(&self) -> Option<usize> {
self.data.offset()
}
}
#[derive(Debug)]
struct RawField(FieldData);
impl RawField {
fn new(name: Option<String>,
ty: ItemId,
comment: Option<String>,
annotations: Option<Annotations>,
bitfield: Option<u32>,
mutable: bool,
offset: Option<usize>)
-> RawField {
RawField(FieldData {
name: name,
ty: ty,
comment: comment,
annotations: annotations.unwrap_or_default(),
bitfield: bitfield,
mutable: mutable,
offset: offset,
})
}
}
impl FieldMethods for RawField {
fn name(&self) -> Option<&str> {
self.0.name()
}
fn ty(&self) -> ItemId {
self.0.ty()
}
fn comment(&self) -> Option<&str> {
self.0.comment()
}
fn bitfield(&self) -> Option<u32> {
self.0.bitfield()
}
fn is_mutable(&self) -> bool {
self.0.is_mutable()
}
fn annotations(&self) -> &Annotations {
self.0.annotations()
}
fn offset(&self) -> Option<usize> {
self.0.offset()
}
}
fn raw_fields_to_fields_and_bitfield_units<I>(ctx: &BindgenContext,
raw_fields: I)
-> Vec<Field>
where I: IntoIterator<Item=RawField>
{
let mut raw_fields = raw_fields.into_iter().fuse().peekable();
let mut fields = vec![];
let mut bitfield_unit_count = 0;
loop {
{
let non_bitfields = raw_fields
.by_ref()
.peeking_take_while(|f| f.bitfield().is_none())
.map(|f| Field::DataMember(f.0));
fields.extend(non_bitfields);
}
let mut bitfields = raw_fields
.by_ref()
.peeking_take_while(|f| f.bitfield().is_some())
.peekable();
if bitfields.peek().is_none() {
break;
}
bitfields_to_allocation_units(ctx,
&mut bitfield_unit_count,
&mut fields,
bitfields);
}
assert!(raw_fields.next().is_none(),
"The above loop should consume all items in `raw_fields`");
fields
}
fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext,
bitfield_unit_count: &mut usize,
mut fields: &mut E,
raw_bitfields: I)
where E: Extend<Field>,
I: IntoIterator<Item=RawField>
{
assert!(ctx.collected_typerefs());
fn flush_allocation_unit<E>(mut fields: &mut E,
bitfield_unit_count: &mut usize,
unit_size_in_bits: usize,
unit_align_in_bits: usize,
bitfields: Vec<Bitfield>)
where E: Extend<Field>
{
*bitfield_unit_count += 1;
let align = bytes_from_bits_pow2(unit_align_in_bits);
let size = align_to(unit_size_in_bits, align * 8) / 8;
let layout = Layout::new(size, align);
fields.extend(Some(Field::Bitfields(BitfieldUnit {
nth: *bitfield_unit_count,
layout: layout,
bitfields: 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![];
const is_ms_struct: bool = false;
for bitfield in raw_bitfields {
let bitfield_width = bitfield.bitfield().unwrap() as usize;
let bitfield_layout =
ctx.resolve_type(bitfield.ty())
.layout(ctx)
.expect("Bitfield without layout? Gah!");
let bitfield_size = bitfield_layout.size;
let bitfield_align = bitfield_layout.align;
let mut offset = unit_size_in_bits;
if is_ms_struct {
if unit_size_in_bits != 0 &&
(bitfield_width == 0 ||
bitfield_width > unfilled_bits_in_unit) {
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::replace(&mut bitfields_in_unit, vec![]));
#[allow(unused_assignments)]
{
unit_size_in_bits = 0;
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);
}
}
if bitfield.name().is_some() {
bitfields_in_unit.push(Bitfield::new(offset, bitfield));
}
max_align = cmp::max(max_align, bitfield_align);
unit_align = cmp::max(unit_align, bitfield_width);
unit_size_in_bits = offset + bitfield_width;
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_allocation_unit(fields,
bitfield_unit_count,
unit_size_in_bits,
unit_align,
bitfields_in_unit);
}
}
#[derive(Debug)]
enum CompFields {
BeforeComputingBitfieldUnits(Vec<RawField>),
AfterComputingBitfieldUnits(Vec<Field>),
}
impl Default for CompFields {
fn default() -> CompFields {
CompFields::BeforeComputingBitfieldUnits(vec![])
}
}
impl CompFields {
fn append_raw_field(&mut self, raw: RawField) {
match *self {
CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
raws.push(raw);
}
CompFields::AfterComputingBitfieldUnits(_) => {
panic!("Must not append new fields after computing bitfield allocation units");
}
}
}
fn compute_bitfield_units(&mut self, ctx: &BindgenContext) {
let raws = match *self {
CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
mem::replace(raws, vec![])
}
CompFields::AfterComputingBitfieldUnits(_) => {
panic!("Already computed bitfield units");
}
};
let fields_and_units = raw_fields_to_fields_and_bitfield_units(ctx, raws);
mem::replace(self, CompFields::AfterComputingBitfieldUnits(fields_and_units));
}
}
impl Trace for CompFields {
type Extra = ();
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
where T: Tracer,
{
match *self {
CompFields::BeforeComputingBitfieldUnits(ref fields) => {
for f in fields {
tracer.visit_kind(f.ty(), EdgeKind::Field);
}
}
CompFields::AfterComputingBitfieldUnits(ref fields) => {
for f in fields {
f.trace(context, tracer, &());
}
}
}
}
}
#[derive(Clone, Debug)]
pub struct FieldData {
name: Option<String>,
ty: ItemId,
comment: Option<String>,
annotations: Annotations,
bitfield: Option<u32>,
mutable: bool,
offset: Option<usize>,
}
impl FieldMethods for FieldData {
fn name(&self) -> Option<&str> {
self.name.as_ref().map(|n| &**n)
}
fn ty(&self) -> ItemId {
self.ty
}
fn comment(&self) -> Option<&str> {
self.comment.as_ref().map(|c| &**c)
}
fn bitfield(&self) -> Option<u32> {
self.bitfield
}
fn is_mutable(&self) -> bool {
self.mutable
}
fn annotations(&self) -> &Annotations {
&self.annotations
}
fn offset(&self) -> Option<usize> {
self.offset
}
}
impl<'a> CanDeriveDefault<'a> for Field {
type Extra = ();
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
match *self {
Field::DataMember(ref data) => data.ty.can_derive_default(ctx, ()),
Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => bitfields.iter().all(|b| {
b.ty().can_derive_default(ctx, ())
}),
}
}
}
impl<'a> CanDeriveCopy<'a> for Field {
type Extra = ();
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
match *self {
Field::DataMember(ref data) => data.ty.can_derive_copy(ctx, ()),
Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => bitfields.iter().all(|b| {
b.ty().can_derive_copy(ctx, ())
}),
}
}
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
match *self {
Field::DataMember(ref data) => data.ty.can_derive_copy_in_array(ctx, ()),
Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => bitfields.iter().all(|b| {
b.ty().can_derive_copy_in_array(ctx, ())
}),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BaseKind {
Normal,
Virtual,
}
#[derive(Clone, Debug)]
pub struct Base {
pub ty: ItemId,
pub kind: BaseKind,
}
impl Base {
pub fn is_virtual(&self) -> bool {
self.kind == BaseKind::Virtual
}
}
#[derive(Debug)]
pub struct CompInfo {
kind: CompKind,
fields: CompFields,
template_params: Vec<ItemId>,
methods: Vec<Method>,
constructors: Vec<ItemId>,
destructor: Option<(bool, ItemId)>,
base_members: Vec<Base>,
inner_types: Vec<ItemId>,
inner_vars: Vec<ItemId>,
has_own_virtual_method: bool,
has_destructor: bool,
has_nonempty_base: bool,
has_non_type_template_params: bool,
packed: bool,
found_unknown_attr: bool,
detect_derive_default_cycle: Cell<bool>,
detect_has_destructor_cycle: Cell<bool>,
is_forward_declaration: bool,
}
impl CompInfo {
pub fn new(kind: CompKind) -> Self {
CompInfo {
kind: 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,
packed: false,
found_unknown_attr: false,
detect_derive_default_cycle: Cell::new(false),
detect_has_destructor_cycle: Cell::new(false),
is_forward_declaration: false,
}
}
pub fn is_unsized(&self, ctx: &BindgenContext, itemid: &ItemId) -> bool {
!ctx.lookup_item_id_has_vtable(itemid) && self.fields().is_empty() &&
self.base_members.iter().all(|base| {
ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx, &base.ty)
})
}
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
if self.detect_has_destructor_cycle.get() {
warn!("Cycle detected looking for destructors");
return false;
}
self.detect_has_destructor_cycle.set(true);
let has_destructor = self.has_destructor ||
match self.kind {
CompKind::Union => false,
CompKind::Struct => {
self.base_members.iter().any(|base| {
ctx.resolve_type(base.ty).has_destructor(ctx)
}) ||
self.fields().iter().any(|field| {
field.has_destructor(ctx)
})
}
};
self.detect_has_destructor_cycle.set(false);
has_destructor
}
pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
use std::cmp;
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 = field.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))
}
pub fn fields(&self) -> &[Field] {
match self.fields {
CompFields::AfterComputingBitfieldUnits(ref fields) => fields,
CompFields::BeforeComputingBitfieldUnits(_) => {
panic!("Should always have computed bitfield units first");
}
}
}
pub fn has_non_type_template_params(&self) -> bool {
self.has_non_type_template_params
}
pub fn has_own_virtual_method(&self) -> bool {
return self.has_own_virtual_method;
}
pub fn methods(&self) -> &[Method] {
&self.methods
}
pub fn constructors(&self) -> &[ItemId] {
&self.constructors
}
pub fn destructor(&self) -> Option<(bool, ItemId)> {
self.destructor
}
pub fn kind(&self) -> CompKind {
self.kind
}
pub fn is_union(&self) -> bool {
self.kind() == CompKind::Union
}
pub fn base_members(&self) -> &[Base] {
&self.base_members
}
pub fn from_ty(potential_id: ItemId,
ty: &clang::Type,
location: Option<clang::Cursor>,
ctx: &mut BindgenContext)
-> Result<Self, ParseError> {
use clang_sys::*;
assert!(ty.template_args().is_none(),
"We handle template instantiations elsewhere");
let mut cursor = ty.declaration();
let mut kind = Self::kind_from_cursor(&cursor);
if kind.is_err() {
if let Some(location) = location {
kind = Self::kind_from_cursor(&location);
cursor = location;
}
}
let kind = 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,
});
let mut maybe_anonymous_struct_field = None;
cursor.visit(|cur| {
if cur.kind() != CXCursor_FieldDecl {
if let Some((ty, clang_ty, offset)) =
maybe_anonymous_struct_field.take() {
if cur.kind() == CXCursor_TypedefDecl &&
cur.typedef_type().unwrap().canonical_type() == clang_ty {
} else {
let field =
RawField::new(None, ty, None, None, None, false, offset);
ci.fields.append_raw_field(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 = RawField::new(None,
ty,
None,
None,
None,
false,
offset);
ci.fields.append_raw_field(field);
}
}
let bit_width = cur.bit_width();
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_mutable = cursor.is_mutable_field();
let offset = cur.offset_of_field().ok();
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_mutable,
offset);
ci.fields.append_raw_field(field);
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 => {
let is_inner_struct = cur.semantic_parent() == cursor ||
cur.is_definition();
if !is_inner_struct {
return CXChildVisit_Continue;
}
let inner = Item::parse(cur, Some(potential_id), ctx)
.expect("Inner ClassDecl");
ci.inner_types.push(inner);
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 => {
let param = Item::named_type(None, cur, ctx)
.expect("Item::named_type 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 type_id =
Item::from_ty_or_ref(cur.cur_type(), 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_own_virtual_method |= is_virtual;
if !ci.template_params.is_empty() {
return CXChildVisit_Continue;
}
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);
}
CXCursor_Destructor => {
ci.destructor = Some((is_virtual, signature));
}
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);
}
}
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, _, offset)) = maybe_anonymous_struct_field {
let field =
RawField::new(None, ty, None, None, None, false, offset);
ci.fields.append_raw_field(field);
}
Ok(ci)
}
fn kind_from_cursor(cursor: &clang::Cursor)
-> Result<CompKind, ParseError> {
use clang_sys::*;
Ok(match cursor.kind() {
CXCursor_UnionDecl => CompKind::Union,
CXCursor_ClassDecl |
CXCursor_StructDecl => CompKind::Struct,
CXCursor_CXXBaseSpecifier |
CXCursor_ClassTemplatePartialSpecialization |
CXCursor_ClassTemplate => {
match cursor.template_kind() {
CXCursor_UnionDecl => CompKind::Union,
_ => CompKind::Struct,
}
}
_ => {
warn!("Unknown kind for comp type: {:?}", cursor);
return Err(ParseError::Continue);
}
})
}
pub fn inner_types(&self) -> &[ItemId] {
&self.inner_types
}
pub fn inner_vars(&self) -> &[ItemId] {
&self.inner_vars
}
pub fn found_unknown_attr(&self) -> bool {
self.found_unknown_attr
}
pub fn packed(&self) -> bool {
self.packed
}
pub fn needs_explicit_vtable(&self, ctx: &BindgenContext, item: &Item) -> bool {
ctx.lookup_item_id_has_vtable(&item.id()) &&
!self.base_members.iter().any(|base| {
ctx.resolve_type(base.ty)
.canonical_type(ctx)
.as_comp()
.map_or(false, |_| ctx.lookup_item_id_has_vtable(&base.ty))
})
}
pub fn is_forward_declaration(&self) -> bool {
self.is_forward_declaration
}
pub fn compute_bitfield_units(&mut self, ctx: &BindgenContext) {
self.fields.compute_bitfield_units(ctx);
}
}
impl DotAttributes for CompInfo {
fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
where W: io::Write
{
writeln!(out, "<tr><td>CompKind</td><td>{:?}</td></tr>", self.kind)?;
if self.has_own_virtual_method {
writeln!(out, "<tr><td>has_vtable</td><td>true</td></tr>")?;
}
if self.has_destructor {
writeln!(out, "<tr><td>has_destructor</td><td>true</td></tr>")?;
}
if self.has_nonempty_base {
writeln!(out, "<tr><td>has_nonempty_base</td><td>true</td></tr>")?;
}
if self.has_non_type_template_params {
writeln!(out, "<tr><td>has_non_type_template_params</td><td>true</td></tr>")?;
}
if self.packed {
writeln!(out, "<tr><td>packed</td><td>true</td></tr>")?;
}
if self.is_forward_declaration {
writeln!(out, "<tr><td>is_forward_declaration</td><td>true</td></tr>")?;
}
if !self.fields().is_empty() {
writeln!(out, r#"<tr><td>fields</td><td><table border="0">"#)?;
for field in self.fields() {
field.dot_attributes(ctx, out)?;
}
writeln!(out, "</table></td></tr>")?;
}
Ok(())
}
}
impl IsOpaque for CompInfo {
type Extra = ();
fn is_opaque(&self, _: &BindgenContext, _: &()) -> bool {
self.has_non_type_template_params
}
}
impl TemplateParameters for CompInfo {
fn self_template_params(&self,
_ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
if self.template_params.is_empty() {
None
} else {
Some(self.template_params.clone())
}
}
}
impl<'a> CanDeriveDefault<'a> for CompInfo {
type Extra = (&'a Item, Option<Layout>);
fn can_derive_default(&self,
ctx: &BindgenContext,
(item, layout): (&Item, Option<Layout>))
-> bool {
if self.detect_derive_default_cycle.get() {
warn!("Derive default cycle detected!");
return true;
}
if layout.map_or(false, |l| l.align > RUST_DERIVE_IN_ARRAY_LIMIT) {
return false;
}
if self.kind == CompKind::Union {
if ctx.options().unstable_rust {
return false;
}
return layout.map_or(true, |l| l.opaque().can_derive_default(ctx, ()));
}
if self.has_non_type_template_params {
return layout.map_or(true, |l| l.opaque().can_derive_default(ctx, ()));
}
self.detect_derive_default_cycle.set(true);
let can_derive_default = !ctx.lookup_item_id_has_vtable(&item.id()) &&
!self.needs_explicit_vtable(ctx, item) &&
self.base_members
.iter()
.all(|base| base.ty.can_derive_default(ctx, ())) &&
self.fields()
.iter()
.all(|f| f.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(true, |l| l.opaque().can_derive_copy(ctx, ()));
}
if self.has_destructor(ctx) {
return false;
}
if self.kind == CompKind::Union {
if !ctx.options().unstable_rust {
return true;
}
if !self.template_params.is_empty() ||
item.used_template_params(ctx).is_some() {
return false;
}
}
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,
{
let params = item.all_template_params(context).unwrap_or(vec![]);
for p in params {
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
}
for &ty in self.inner_types() {
tracer.visit_kind(ty, EdgeKind::InnerType);
}
for &var in self.inner_vars() {
tracer.visit_kind(var, EdgeKind::InnerVar);
}
for method in self.methods() {
if method.is_destructor() {
tracer.visit_kind(method.signature, EdgeKind::Destructor);
} else {
tracer.visit_kind(method.signature, EdgeKind::Method);
}
}
for &ctor in self.constructors() {
tracer.visit_kind(ctor, EdgeKind::Constructor);
}
if item.is_opaque(context, &()) {
return;
}
for base in self.base_members() {
tracer.visit_kind(base.ty, EdgeKind::BaseMember);
}
self.fields.trace(context, tracer, &());
}
}