1896 lines
60 KiB
Rust
1896 lines
60 KiB
Rust
//! Compound types (unions and structs) in our intermediate representation.
|
||
|
||
use itertools::Itertools;
|
||
|
||
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 std::cmp;
|
||
use std::io;
|
||
use std::mem;
|
||
|
||
/// The kind of compound type.
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||
pub(crate) enum CompKind {
|
||
/// A struct.
|
||
Struct,
|
||
/// A union.
|
||
Union,
|
||
}
|
||
|
||
/// The kind of C++ method.
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||
pub(crate) 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(crate) fn is_destructor(&self) -> bool {
|
||
matches!(
|
||
*self,
|
||
MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
|
||
)
|
||
}
|
||
|
||
/// Is this a pure virtual method?
|
||
pub(crate) 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(crate) 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(crate) fn new(
|
||
kind: MethodKind,
|
||
signature: FunctionId,
|
||
is_const: bool,
|
||
) -> Self {
|
||
Method {
|
||
kind,
|
||
signature,
|
||
is_const,
|
||
}
|
||
}
|
||
|
||
/// What kind of method is this?
|
||
pub(crate) fn kind(&self) -> MethodKind {
|
||
self.kind
|
||
}
|
||
|
||
/// Is this a constructor?
|
||
pub(crate) fn is_constructor(&self) -> bool {
|
||
self.kind == MethodKind::Constructor
|
||
}
|
||
|
||
/// Is this a virtual method?
|
||
pub(crate) fn is_virtual(&self) -> bool {
|
||
matches!(
|
||
self.kind,
|
||
MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
|
||
)
|
||
}
|
||
|
||
/// Is this a static method?
|
||
pub(crate) fn is_static(&self) -> bool {
|
||
self.kind == MethodKind::Static
|
||
}
|
||
|
||
/// Get the ID for the `Function` signature for this method.
|
||
pub(crate) fn signature(&self) -> FunctionId {
|
||
self.signature
|
||
}
|
||
|
||
/// Is this a const qualified method?
|
||
pub(crate) fn is_const(&self) -> bool {
|
||
self.is_const
|
||
}
|
||
}
|
||
|
||
/// Methods common to the various field types.
|
||
pub(crate) trait FieldMethods {
|
||
/// Get the name of this field.
|
||
fn name(&self) -> Option<&str>;
|
||
|
||
/// Get the type of this field.
|
||
fn ty(&self) -> TypeId;
|
||
|
||
/// Get the comment for this field.
|
||
fn comment(&self) -> Option<&str>;
|
||
|
||
/// If this is a bitfield, how many bits does it need?
|
||
fn bitfield_width(&self) -> Option<u32>;
|
||
|
||
/// Is this feild declared public?
|
||
fn is_public(&self) -> bool;
|
||
|
||
/// Get the annotations for this field.
|
||
fn annotations(&self) -> &Annotations;
|
||
|
||
/// The offset of the field (in bits)
|
||
fn offset(&self) -> Option<usize>;
|
||
}
|
||
|
||
/// A contiguous set of logical bitfields that live within the same physical
|
||
/// allocation unit. See 9.2.4 [class.bit] in the C++ standard and [section
|
||
/// 2.4.II.1 in the Itanium C++
|
||
/// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types).
|
||
#[derive(Debug)]
|
||
pub(crate) struct BitfieldUnit {
|
||
nth: usize,
|
||
layout: Layout,
|
||
bitfields: Vec<Bitfield>,
|
||
}
|
||
|
||
impl BitfieldUnit {
|
||
/// Get the 1-based index of this bitfield unit within its containing
|
||
/// struct. Useful for generating a Rust struct's field name for this unit
|
||
/// of bitfields.
|
||
pub(crate) fn nth(&self) -> usize {
|
||
self.nth
|
||
}
|
||
|
||
/// Get the layout within which these bitfields reside.
|
||
pub(crate) fn layout(&self) -> Layout {
|
||
self.layout
|
||
}
|
||
|
||
/// Get the bitfields within this unit.
|
||
pub(crate) fn bitfields(&self) -> &[Bitfield] {
|
||
&self.bitfields
|
||
}
|
||
}
|
||
|
||
/// A struct representing a C++ field.
|
||
#[derive(Debug)]
|
||
pub(crate) 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(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
|
||
match *self {
|
||
Field::Bitfields(BitfieldUnit { layout, .. }) => Some(layout),
|
||
Field::DataMember(ref data) => {
|
||
ctx.resolve_type(data.ty).layout(ctx)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Trace for Field {
|
||
type Extra = ();
|
||
|
||
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
|
||
where
|
||
T: Tracer,
|
||
{
|
||
match *self {
|
||
Field::DataMember(ref data) => {
|
||
tracer.visit_kind(data.ty.into(), EdgeKind::Field);
|
||
}
|
||
Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => {
|
||
for bf in bitfields {
|
||
tracer.visit_kind(bf.ty().into(), EdgeKind::Field);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
impl DotAttributes for Field {
|
||
fn dot_attributes<W>(
|
||
&self,
|
||
ctx: &BindgenContext,
|
||
out: &mut W,
|
||
) -> io::Result<()>
|
||
where
|
||
W: io::Write,
|
||
{
|
||
match *self {
|
||
Field::DataMember(ref data) => data.dot_attributes(ctx, out),
|
||
Field::Bitfields(BitfieldUnit {
|
||
layout,
|
||
ref bitfields,
|
||
..
|
||
}) => {
|
||
writeln!(
|
||
out,
|
||
r#"<tr>
|
||
<td>bitfield unit</td>
|
||
<td>
|
||
<table border="0">
|
||
<tr>
|
||
<td>unit.size</td><td>{}</td>
|
||
</tr>
|
||
<tr>
|
||
<td>unit.align</td><td>{}</td>
|
||
</tr>
|
||
"#,
|
||
layout.size, layout.align
|
||
)?;
|
||
for bf in bitfields {
|
||
bf.dot_attributes(ctx, out)?;
|
||
}
|
||
writeln!(out, "</table></td></tr>")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
impl DotAttributes for FieldData {
|
||
fn dot_attributes<W>(
|
||
&self,
|
||
_ctx: &BindgenContext,
|
||
out: &mut W,
|
||
) -> io::Result<()>
|
||
where
|
||
W: io::Write,
|
||
{
|
||
writeln!(
|
||
out,
|
||
"<tr><td>{}</td><td>{:?}</td></tr>",
|
||
self.name().unwrap_or("(anonymous)"),
|
||
self.ty()
|
||
)
|
||
}
|
||
}
|
||
|
||
impl DotAttributes for Bitfield {
|
||
fn dot_attributes<W>(
|
||
&self,
|
||
_ctx: &BindgenContext,
|
||
out: &mut W,
|
||
) -> io::Result<()>
|
||
where
|
||
W: io::Write,
|
||
{
|
||
writeln!(
|
||
out,
|
||
"<tr><td>{} : {}</td><td>{:?}</td></tr>",
|
||
self.name().unwrap_or("(anonymous)"),
|
||
self.width(),
|
||
self.ty()
|
||
)
|
||
}
|
||
}
|
||
|
||
/// A logical bitfield within some physical bitfield allocation unit.
|
||
#[derive(Debug)]
|
||
pub(crate) struct Bitfield {
|
||
/// Index of the bit within this bitfield's allocation unit where this
|
||
/// bitfield's bits begin.
|
||
offset_into_unit: usize,
|
||
|
||
/// The field data for this bitfield.
|
||
data: FieldData,
|
||
|
||
/// Name of the generated Rust getter for this bitfield.
|
||
///
|
||
/// Should be assigned before codegen.
|
||
getter_name: Option<String>,
|
||
|
||
/// Name of the generated Rust setter for this bitfield.
|
||
///
|
||
/// Should be assigned before codegen.
|
||
setter_name: Option<String>,
|
||
}
|
||
|
||
impl Bitfield {
|
||
/// Construct a new bitfield.
|
||
fn new(offset_into_unit: usize, raw: RawField) -> Bitfield {
|
||
assert!(raw.bitfield_width().is_some());
|
||
|
||
Bitfield {
|
||
offset_into_unit,
|
||
data: raw.0,
|
||
getter_name: None,
|
||
setter_name: None,
|
||
}
|
||
}
|
||
|
||
/// Get the index of the bit within this bitfield's allocation unit where
|
||
/// this bitfield begins.
|
||
pub(crate) fn offset_into_unit(&self) -> usize {
|
||
self.offset_into_unit
|
||
}
|
||
|
||
/// Get the bit width of this bitfield.
|
||
pub(crate) 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(crate) 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(crate) fn setter_name(&self) -> &str {
|
||
assert!(
|
||
self.name().is_some(),
|
||
"`Bitfield::setter_name` called on anonymous field"
|
||
);
|
||
self.setter_name.as_ref().expect(
|
||
"`Bitfield::setter_name` should only be called\
|
||
after assigning bitfield accessor names",
|
||
)
|
||
}
|
||
}
|
||
|
||
impl FieldMethods for Bitfield {
|
||
fn name(&self) -> Option<&str> {
|
||
self.data.name()
|
||
}
|
||
|
||
fn ty(&self) -> TypeId {
|
||
self.data.ty()
|
||
}
|
||
|
||
fn comment(&self) -> Option<&str> {
|
||
self.data.comment()
|
||
}
|
||
|
||
fn bitfield_width(&self) -> Option<u32> {
|
||
self.data.bitfield_width()
|
||
}
|
||
|
||
fn is_public(&self) -> bool {
|
||
self.data.is_public()
|
||
}
|
||
|
||
fn annotations(&self) -> &Annotations {
|
||
self.data.annotations()
|
||
}
|
||
|
||
fn offset(&self) -> Option<usize> {
|
||
self.data.offset()
|
||
}
|
||
}
|
||
|
||
/// A raw field might be either of a plain data member or a bitfield within a
|
||
/// bitfield allocation unit, but we haven't processed it and determined which
|
||
/// yet (which would involve allocating it into a bitfield unit if it is a
|
||
/// bitfield).
|
||
#[derive(Debug)]
|
||
struct RawField(FieldData);
|
||
|
||
impl RawField {
|
||
/// Construct a new `RawField`.
|
||
fn new(
|
||
name: Option<String>,
|
||
ty: TypeId,
|
||
comment: Option<String>,
|
||
annotations: Option<Annotations>,
|
||
bitfield_width: Option<u32>,
|
||
public: bool,
|
||
offset: Option<usize>,
|
||
) -> RawField {
|
||
RawField(FieldData {
|
||
name,
|
||
ty,
|
||
comment,
|
||
annotations: annotations.unwrap_or_default(),
|
||
bitfield_width,
|
||
public,
|
||
offset,
|
||
})
|
||
}
|
||
}
|
||
|
||
impl FieldMethods for RawField {
|
||
fn name(&self) -> Option<&str> {
|
||
self.0.name()
|
||
}
|
||
|
||
fn ty(&self) -> TypeId {
|
||
self.0.ty()
|
||
}
|
||
|
||
fn comment(&self) -> Option<&str> {
|
||
self.0.comment()
|
||
}
|
||
|
||
fn bitfield_width(&self) -> Option<u32> {
|
||
self.0.bitfield_width()
|
||
}
|
||
|
||
fn is_public(&self) -> bool {
|
||
self.0.is_public()
|
||
}
|
||
|
||
fn annotations(&self) -> &Annotations {
|
||
self.0.annotations()
|
||
}
|
||
|
||
fn offset(&self) -> Option<usize> {
|
||
self.0.offset()
|
||
}
|
||
}
|
||
|
||
/// Convert the given ordered set of raw fields into a list of either plain data
|
||
/// members, and/or bitfield units containing multiple bitfields.
|
||
///
|
||
/// If we do not have the layout for a bitfield's type, then we can't reliably
|
||
/// compute its allocation unit. In such cases, we return an error.
|
||
fn raw_fields_to_fields_and_bitfield_units<I>(
|
||
ctx: &BindgenContext,
|
||
raw_fields: I,
|
||
packed: bool,
|
||
) -> Result<(Vec<Field>, bool), ()>
|
||
where
|
||
I: IntoIterator<Item = RawField>,
|
||
{
|
||
let mut raw_fields = raw_fields.into_iter().fuse().peekable();
|
||
let mut fields = vec![];
|
||
let mut bitfield_unit_count = 0;
|
||
|
||
loop {
|
||
// While we have plain old data members, just keep adding them to our
|
||
// resulting fields. We introduce a scope here so that we can use
|
||
// `raw_fields` again after the `by_ref` iterator adaptor is dropped.
|
||
{
|
||
let non_bitfields = raw_fields
|
||
.by_ref()
|
||
.peeking_take_while(|f| f.bitfield_width().is_none())
|
||
.map(|f| Field::DataMember(f.0));
|
||
fields.extend(non_bitfields);
|
||
}
|
||
|
||
// Now gather all the consecutive bitfields. Only consecutive bitfields
|
||
// may potentially share a bitfield allocation unit with each other in
|
||
// the Itanium C++ ABI.
|
||
let mut bitfields = raw_fields
|
||
.by_ref()
|
||
.peeking_take_while(|f| f.bitfield_width().is_some())
|
||
.peekable();
|
||
|
||
if bitfields.peek().is_none() {
|
||
break;
|
||
}
|
||
|
||
bitfields_to_allocation_units(
|
||
ctx,
|
||
&mut bitfield_unit_count,
|
||
&mut fields,
|
||
bitfields,
|
||
packed,
|
||
)?;
|
||
}
|
||
|
||
assert!(
|
||
raw_fields.next().is_none(),
|
||
"The above loop should consume all items in `raw_fields`"
|
||
);
|
||
|
||
Ok((fields, bitfield_unit_count != 0))
|
||
}
|
||
|
||
/// Given a set of contiguous raw bitfields, group and allocate them into
|
||
/// (potentially multiple) bitfield units.
|
||
fn bitfields_to_allocation_units<E, I>(
|
||
ctx: &BindgenContext,
|
||
bitfield_unit_count: &mut usize,
|
||
fields: &mut E,
|
||
raw_bitfields: I,
|
||
packed: bool,
|
||
) -> Result<(), ()>
|
||
where
|
||
E: Extend<Field>,
|
||
I: IntoIterator<Item = RawField>,
|
||
{
|
||
assert!(ctx.collected_typerefs());
|
||
|
||
// NOTE: What follows is reverse-engineered from LLVM's
|
||
// lib/AST/RecordLayoutBuilder.cpp
|
||
//
|
||
// FIXME(emilio): There are some differences between Microsoft and the
|
||
// Itanium ABI, but we'll ignore those and stick to Itanium for now.
|
||
//
|
||
// Also, we need to handle packed bitfields and stuff.
|
||
//
|
||
// TODO(emilio): Take into account C++'s wide bitfields, and
|
||
// packing, sigh.
|
||
|
||
fn flush_allocation_unit<E>(
|
||
fields: &mut E,
|
||
bitfield_unit_count: &mut usize,
|
||
unit_size_in_bits: usize,
|
||
unit_align_in_bits: usize,
|
||
bitfields: Vec<Bitfield>,
|
||
packed: bool,
|
||
) where
|
||
E: Extend<Field>,
|
||
{
|
||
*bitfield_unit_count += 1;
|
||
let align = if packed {
|
||
1
|
||
} else {
|
||
bytes_from_bits_pow2(unit_align_in_bits)
|
||
};
|
||
let size = align_to(unit_size_in_bits, 8) / 8;
|
||
let layout = Layout::new(size, align);
|
||
fields.extend(Some(Field::Bitfields(BitfieldUnit {
|
||
nth: *bitfield_unit_count,
|
||
layout,
|
||
bitfields,
|
||
})));
|
||
}
|
||
|
||
let mut max_align = 0;
|
||
let mut unfilled_bits_in_unit = 0;
|
||
let mut unit_size_in_bits = 0;
|
||
let mut unit_align = 0;
|
||
let mut bitfields_in_unit = vec![];
|
||
|
||
// TODO(emilio): Determine this from attributes or pragma ms_struct
|
||
// directives. Also, perhaps we should check if the target is MSVC?
|
||
const is_ms_struct: bool = false;
|
||
|
||
for bitfield in raw_bitfields {
|
||
let bitfield_width = bitfield.bitfield_width().unwrap() as usize;
|
||
let bitfield_layout =
|
||
ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?;
|
||
let bitfield_size = bitfield_layout.size;
|
||
let bitfield_align = bitfield_layout.align;
|
||
|
||
let mut offset = unit_size_in_bits;
|
||
if !packed {
|
||
if is_ms_struct {
|
||
if unit_size_in_bits != 0 &&
|
||
(bitfield_width == 0 ||
|
||
bitfield_width > unfilled_bits_in_unit)
|
||
{
|
||
// We've reached the end of this allocation unit, so flush it
|
||
// and its bitfields.
|
||
unit_size_in_bits =
|
||
align_to(unit_size_in_bits, unit_align * 8);
|
||
flush_allocation_unit(
|
||
fields,
|
||
bitfield_unit_count,
|
||
unit_size_in_bits,
|
||
unit_align,
|
||
mem::take(&mut bitfields_in_unit),
|
||
packed,
|
||
);
|
||
|
||
// Now we're working on a fresh bitfield allocation unit, so reset
|
||
// the current unit size and alignment.
|
||
offset = 0;
|
||
unit_align = 0;
|
||
}
|
||
} else if offset != 0 &&
|
||
(bitfield_width == 0 ||
|
||
(offset & (bitfield_align * 8 - 1)) + bitfield_width >
|
||
bitfield_size * 8)
|
||
{
|
||
offset = align_to(offset, bitfield_align * 8);
|
||
}
|
||
}
|
||
|
||
// According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not
|
||
// affect the alignment of a structure or union". This makes sense: such
|
||
// bit-fields are only used for padding, and we can't perform an
|
||
// un-aligned read of something we can't read because we can't even name
|
||
// it.
|
||
if bitfield.name().is_some() {
|
||
max_align = cmp::max(max_align, bitfield_align);
|
||
|
||
// NB: The `bitfield_width` here is completely, absolutely
|
||
// intentional. Alignment of the allocation unit is based on the
|
||
// maximum bitfield width, not (directly) on the bitfields' types'
|
||
// alignment.
|
||
unit_align = cmp::max(unit_align, bitfield_width);
|
||
}
|
||
|
||
// Always keep all bitfields around. While unnamed bitifields are used
|
||
// for padding (and usually not needed hereafter), large unnamed
|
||
// bitfields over their types size cause weird allocation size behavior from clang.
|
||
// Therefore, all bitfields needed to be kept around in order to check for this
|
||
// and make the struct opaque in this case
|
||
bitfields_in_unit.push(Bitfield::new(offset, bitfield));
|
||
|
||
unit_size_in_bits = offset + bitfield_width;
|
||
|
||
// Compute what the physical unit's final size would be given what we
|
||
// have seen so far, and use that to compute how many bits are still
|
||
// available in the unit.
|
||
let data_size = align_to(unit_size_in_bits, bitfield_align * 8);
|
||
unfilled_bits_in_unit = data_size - unit_size_in_bits;
|
||
}
|
||
|
||
if unit_size_in_bits != 0 {
|
||
// Flush the last allocation unit and its bitfields.
|
||
flush_allocation_unit(
|
||
fields,
|
||
bitfield_unit_count,
|
||
unit_size_in_bits,
|
||
unit_align,
|
||
bitfields_in_unit,
|
||
packed,
|
||
);
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// A compound structure's fields are initially raw, and have bitfields that
|
||
/// have not been grouped into allocation units. During this time, the fields
|
||
/// are mutable and we build them up during parsing.
|
||
///
|
||
/// Then, once resolving typerefs is completed, we compute all structs' fields'
|
||
/// bitfield allocation units, and they remain frozen and immutable forever
|
||
/// after.
|
||
#[derive(Debug)]
|
||
enum CompFields {
|
||
Before(Vec<RawField>),
|
||
After {
|
||
fields: Vec<Field>,
|
||
has_bitfield_units: bool,
|
||
},
|
||
Error,
|
||
}
|
||
|
||
impl Default for CompFields {
|
||
fn default() -> CompFields {
|
||
CompFields::Before(vec![])
|
||
}
|
||
}
|
||
|
||
impl CompFields {
|
||
fn append_raw_field(&mut self, raw: RawField) {
|
||
match *self {
|
||
CompFields::Before(ref mut raws) => {
|
||
raws.push(raw);
|
||
}
|
||
_ => {
|
||
panic!(
|
||
"Must not append new fields after computing bitfield allocation units"
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) {
|
||
let raws = match *self {
|
||
CompFields::Before(ref mut raws) => mem::take(raws),
|
||
_ => {
|
||
panic!("Already computed bitfield units");
|
||
}
|
||
};
|
||
|
||
let result = raw_fields_to_fields_and_bitfield_units(ctx, raws, packed);
|
||
|
||
match result {
|
||
Ok((fields, has_bitfield_units)) => {
|
||
*self = CompFields::After {
|
||
fields,
|
||
has_bitfield_units,
|
||
};
|
||
}
|
||
Err(()) => {
|
||
*self = CompFields::Error;
|
||
}
|
||
}
|
||
}
|
||
|
||
fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
|
||
let fields = match *self {
|
||
CompFields::After { ref mut fields, .. } => fields,
|
||
// Nothing to do here.
|
||
CompFields::Error => return,
|
||
CompFields::Before(_) => {
|
||
panic!("Not yet computed bitfield units.");
|
||
}
|
||
};
|
||
|
||
fn has_method(
|
||
methods: &[Method],
|
||
ctx: &BindgenContext,
|
||
name: &str,
|
||
) -> bool {
|
||
methods.iter().any(|method| {
|
||
let method_name = ctx.resolve_func(method.signature()).name();
|
||
method_name == name || ctx.rust_mangle(method_name) == name
|
||
})
|
||
}
|
||
|
||
struct AccessorNamesPair {
|
||
getter: String,
|
||
setter: String,
|
||
}
|
||
|
||
let mut accessor_names: HashMap<String, AccessorNamesPair> = fields
|
||
.iter()
|
||
.flat_map(|field| match *field {
|
||
Field::Bitfields(ref bu) => &*bu.bitfields,
|
||
Field::DataMember(_) => &[],
|
||
})
|
||
.filter_map(|bitfield| bitfield.name())
|
||
.map(|bitfield_name| {
|
||
let bitfield_name = bitfield_name.to_string();
|
||
let getter = {
|
||
let mut getter =
|
||
ctx.rust_mangle(&bitfield_name).to_string();
|
||
if has_method(methods, ctx, &getter) {
|
||
getter.push_str("_bindgen_bitfield");
|
||
}
|
||
getter
|
||
};
|
||
let setter = {
|
||
let setter = format!("set_{}", bitfield_name);
|
||
let mut setter = ctx.rust_mangle(&setter).to_string();
|
||
if has_method(methods, ctx, &setter) {
|
||
setter.push_str("_bindgen_bitfield");
|
||
}
|
||
setter
|
||
};
|
||
(bitfield_name, AccessorNamesPair { getter, setter })
|
||
})
|
||
.collect();
|
||
|
||
let mut anon_field_counter = 0;
|
||
for field in fields.iter_mut() {
|
||
match *field {
|
||
Field::DataMember(FieldData { ref mut name, .. }) => {
|
||
if name.is_some() {
|
||
continue;
|
||
}
|
||
|
||
anon_field_counter += 1;
|
||
*name = Some(format!(
|
||
"{}{}",
|
||
ctx.options().anon_fields_prefix,
|
||
anon_field_counter
|
||
));
|
||
}
|
||
Field::Bitfields(ref mut bu) => {
|
||
for bitfield in &mut bu.bitfields {
|
||
if bitfield.name().is_none() {
|
||
continue;
|
||
}
|
||
|
||
if let Some(AccessorNamesPair { getter, setter }) =
|
||
accessor_names.remove(bitfield.name().unwrap())
|
||
{
|
||
bitfield.getter_name = Some(getter);
|
||
bitfield.setter_name = Some(setter);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Trace for CompFields {
|
||
type Extra = ();
|
||
|
||
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
|
||
where
|
||
T: Tracer,
|
||
{
|
||
match *self {
|
||
CompFields::Error => {}
|
||
CompFields::Before(ref fields) => {
|
||
for f in fields {
|
||
tracer.visit_kind(f.ty().into(), EdgeKind::Field);
|
||
}
|
||
}
|
||
CompFields::After { ref fields, .. } => {
|
||
for f in fields {
|
||
f.trace(context, tracer, &());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Common data shared across different field types.
|
||
#[derive(Clone, Debug)]
|
||
pub(crate) struct FieldData {
|
||
/// The name of the field, empty if it's an unnamed bitfield width.
|
||
name: Option<String>,
|
||
|
||
/// The inner type.
|
||
ty: TypeId,
|
||
|
||
/// The doc comment on the field if any.
|
||
comment: Option<String>,
|
||
|
||
/// Annotations for this field, or the default.
|
||
annotations: Annotations,
|
||
|
||
/// If this field is a bitfield, and how many bits does it contain if it is.
|
||
bitfield_width: Option<u32>,
|
||
|
||
/// If the C++ field is declared `public`
|
||
public: bool,
|
||
|
||
/// The offset of the field (in bits)
|
||
offset: Option<usize>,
|
||
}
|
||
|
||
impl FieldMethods for FieldData {
|
||
fn name(&self) -> Option<&str> {
|
||
self.name.as_deref()
|
||
}
|
||
|
||
fn ty(&self) -> TypeId {
|
||
self.ty
|
||
}
|
||
|
||
fn comment(&self) -> Option<&str> {
|
||
self.comment.as_deref()
|
||
}
|
||
|
||
fn bitfield_width(&self) -> Option<u32> {
|
||
self.bitfield_width
|
||
}
|
||
|
||
fn is_public(&self) -> bool {
|
||
self.public
|
||
}
|
||
|
||
fn annotations(&self) -> &Annotations {
|
||
&self.annotations
|
||
}
|
||
|
||
fn offset(&self) -> Option<usize> {
|
||
self.offset
|
||
}
|
||
}
|
||
|
||
/// The kind of inheritance a base class is using.
|
||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||
pub(crate) 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(crate) struct Base {
|
||
/// The type of this base class.
|
||
pub(crate) ty: TypeId,
|
||
/// The kind of inheritance we're doing.
|
||
pub(crate) kind: BaseKind,
|
||
/// Name of the field in which this base should be stored.
|
||
pub(crate) field_name: String,
|
||
/// Whether this base is inherited from publically.
|
||
pub(crate) is_pub: bool,
|
||
}
|
||
|
||
impl Base {
|
||
/// Whether this base class is inheriting virtually.
|
||
pub(crate) fn is_virtual(&self) -> bool {
|
||
self.kind == BaseKind::Virtual
|
||
}
|
||
|
||
/// Whether this base class should have it's own field for storage.
|
||
pub(crate) 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(crate) 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(crate) struct CompInfo {
|
||
/// Whether this is a struct or a union.
|
||
kind: CompKind,
|
||
|
||
/// The members of this struct or union.
|
||
fields: CompFields,
|
||
|
||
/// The abstract template parameters of this class. Note that these are NOT
|
||
/// concrete template arguments, and should always be a
|
||
/// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see
|
||
/// `TypeKind::TemplateInstantiation`.
|
||
template_params: Vec<TypeId>,
|
||
|
||
/// The method declarations inside this class, if in C++ mode.
|
||
methods: Vec<Method>,
|
||
|
||
/// The different constructors this struct or class contains.
|
||
constructors: Vec<FunctionId>,
|
||
|
||
/// The destructor of this type. The bool represents whether this destructor
|
||
/// is virtual.
|
||
destructor: Option<(MethodKind, FunctionId)>,
|
||
|
||
/// Vector of classes this one inherits from.
|
||
base_members: Vec<Base>,
|
||
|
||
/// The inner types that were declared inside this class, in something like:
|
||
///
|
||
/// class Foo {
|
||
/// typedef int FooTy;
|
||
/// struct Bar {
|
||
/// int baz;
|
||
/// };
|
||
/// }
|
||
///
|
||
/// static Foo::Bar const = {3};
|
||
inner_types: Vec<TypeId>,
|
||
|
||
/// Set of static constants declared inside this class.
|
||
inner_vars: Vec<VarId>,
|
||
|
||
/// Whether this type should generate an vtable (TODO: Should be able to
|
||
/// look at the virtual methods and ditch this field).
|
||
has_own_virtual_method: bool,
|
||
|
||
/// Whether this type has destructor.
|
||
has_destructor: bool,
|
||
|
||
/// Whether this type has a base type with more than one member.
|
||
///
|
||
/// TODO: We should be able to compute this.
|
||
has_nonempty_base: bool,
|
||
|
||
/// If this type has a template parameter which is not a type (e.g.: a
|
||
/// size_t)
|
||
has_non_type_template_params: bool,
|
||
|
||
/// Whether this type has a bit field member whose width couldn't be
|
||
/// evaluated (e.g. if it depends on a template parameter). We generate an
|
||
/// opaque type in this case.
|
||
has_unevaluable_bit_field_width: bool,
|
||
|
||
/// Whether we saw `__attribute__((packed))` on or within this type.
|
||
packed_attr: bool,
|
||
|
||
/// Used to know if we've found an opaque attribute that could cause us to
|
||
/// generate a type with invalid layout. This is explicitly used to avoid us
|
||
/// generating bad alignments when parsing types like max_align_t.
|
||
///
|
||
/// It's not clear what the behavior should be here, if generating the item
|
||
/// and pray, or behave as an opaque type.
|
||
found_unknown_attr: bool,
|
||
|
||
/// Used to indicate when a struct has been forward declared. Usually used
|
||
/// in headers so that APIs can't modify them directly.
|
||
is_forward_declaration: bool,
|
||
}
|
||
|
||
impl CompInfo {
|
||
/// Construct a new compound type.
|
||
pub(crate) 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(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
|
||
// We can't do better than clang here, sorry.
|
||
if self.kind == CompKind::Struct {
|
||
return None;
|
||
}
|
||
|
||
// By definition, we don't have the right layout information here if
|
||
// we're a forward declaration.
|
||
if self.is_forward_declaration() {
|
||
return None;
|
||
}
|
||
|
||
// empty union case
|
||
if !self.has_fields() {
|
||
return None;
|
||
}
|
||
|
||
let mut max_size = 0;
|
||
// Don't allow align(0)
|
||
let mut max_align = 1;
|
||
self.each_known_field_layout(ctx, |layout| {
|
||
max_size = cmp::max(max_size, layout.size);
|
||
max_align = cmp::max(max_align, layout.align);
|
||
});
|
||
|
||
Some(Layout::new(max_size, max_align))
|
||
}
|
||
|
||
/// Get this type's set of fields.
|
||
pub(crate) 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(crate) 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(crate) 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(crate) fn has_own_virtual_method(&self) -> bool {
|
||
self.has_own_virtual_method
|
||
}
|
||
|
||
/// Did we see a destructor when parsing this type?
|
||
pub(crate) fn has_own_destructor(&self) -> bool {
|
||
self.has_destructor
|
||
}
|
||
|
||
/// Get this type's set of methods.
|
||
pub(crate) fn methods(&self) -> &[Method] {
|
||
&self.methods
|
||
}
|
||
|
||
/// Get this type's set of constructors.
|
||
pub(crate) fn constructors(&self) -> &[FunctionId] {
|
||
&self.constructors
|
||
}
|
||
|
||
/// Get this type's destructor.
|
||
pub(crate) fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
|
||
self.destructor
|
||
}
|
||
|
||
/// What kind of compound type is this?
|
||
pub(crate) fn kind(&self) -> CompKind {
|
||
self.kind
|
||
}
|
||
|
||
/// Is this a union?
|
||
pub(crate) fn is_union(&self) -> bool {
|
||
self.kind() == CompKind::Union
|
||
}
|
||
|
||
/// The set of types that this one inherits from.
|
||
pub(crate) fn base_members(&self) -> &[Base] {
|
||
&self.base_members
|
||
}
|
||
|
||
/// Construct a new compound type from a Clang type.
|
||
pub(crate) fn from_ty(
|
||
potential_id: ItemId,
|
||
ty: &clang::Type,
|
||
location: Option<clang::Cursor>,
|
||
ctx: &mut BindgenContext,
|
||
) -> Result<Self, ParseError> {
|
||
use clang_sys::*;
|
||
assert!(
|
||
ty.template_args().is_none(),
|
||
"We handle template instantiations elsewhere"
|
||
);
|
||
|
||
let mut cursor = ty.declaration();
|
||
let mut kind = Self::kind_from_cursor(&cursor);
|
||
if kind.is_err() {
|
||
if let Some(location) = location {
|
||
kind = Self::kind_from_cursor(&location);
|
||
cursor = location;
|
||
}
|
||
}
|
||
|
||
let kind = kind?;
|
||
|
||
debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
|
||
|
||
let mut ci = CompInfo::new(kind);
|
||
ci.is_forward_declaration =
|
||
location.map_or(true, |cur| match cur.kind() {
|
||
CXCursor_ParmDecl => true,
|
||
CXCursor_StructDecl | CXCursor_UnionDecl |
|
||
CXCursor_ClassDecl => !cur.is_definition(),
|
||
_ => false,
|
||
});
|
||
|
||
let mut maybe_anonymous_struct_field = None;
|
||
cursor.visit(|cur| {
|
||
if cur.kind() != CXCursor_FieldDecl {
|
||
if let Some((ty, clang_ty, public, offset)) =
|
||
maybe_anonymous_struct_field.take()
|
||
{
|
||
if cur.kind() == CXCursor_TypedefDecl &&
|
||
cur.typedef_type().unwrap().canonical_type() ==
|
||
clang_ty
|
||
{
|
||
// Typedefs of anonymous structs appear later in the ast
|
||
// than the struct itself, that would otherwise be an
|
||
// anonymous field. Detect that case here, and do
|
||
// nothing.
|
||
} else {
|
||
let field = RawField::new(
|
||
None, ty, None, None, None, public, offset,
|
||
);
|
||
ci.fields.append_raw_field(field);
|
||
}
|
||
}
|
||
}
|
||
|
||
match cur.kind() {
|
||
CXCursor_FieldDecl => {
|
||
if let Some((ty, clang_ty, public, offset)) =
|
||
maybe_anonymous_struct_field.take()
|
||
{
|
||
let mut used = false;
|
||
cur.visit(|child| {
|
||
if child.cur_type() == clang_ty {
|
||
used = true;
|
||
}
|
||
CXChildVisit_Continue
|
||
});
|
||
|
||
if !used {
|
||
let field = RawField::new(
|
||
None, ty, None, None, None, public, offset,
|
||
);
|
||
ci.fields.append_raw_field(field);
|
||
}
|
||
}
|
||
|
||
let bit_width = if cur.is_bit_field() {
|
||
let width = cur.bit_width();
|
||
|
||
// Make opaque type if the bit width couldn't be
|
||
// evaluated.
|
||
if width.is_none() {
|
||
ci.has_unevaluable_bit_field_width = true;
|
||
return CXChildVisit_Break;
|
||
}
|
||
|
||
width
|
||
} else {
|
||
None
|
||
};
|
||
|
||
let field_type = Item::from_ty_or_ref(
|
||
cur.cur_type(),
|
||
cur,
|
||
Some(potential_id),
|
||
ctx,
|
||
);
|
||
|
||
let comment = cur.raw_comment();
|
||
let annotations = Annotations::new(&cur);
|
||
let name = cur.spelling();
|
||
let is_public = cur.public_accessible();
|
||
let offset = cur.offset_of_field().ok();
|
||
|
||
// Name can be empty if there are bitfields, for example,
|
||
// see tests/headers/struct_with_bitfields.h
|
||
assert!(
|
||
!name.is_empty() || bit_width.is_some(),
|
||
"Empty field name?"
|
||
);
|
||
|
||
let name = if name.is_empty() { None } else { Some(name) };
|
||
|
||
let field = RawField::new(
|
||
name,
|
||
field_type,
|
||
comment,
|
||
annotations,
|
||
bit_width,
|
||
is_public,
|
||
offset,
|
||
);
|
||
ci.fields.append_raw_field(field);
|
||
|
||
// No we look for things like attributes and stuff.
|
||
cur.visit(|cur| {
|
||
if cur.kind() == CXCursor_UnexposedAttr {
|
||
ci.found_unknown_attr = true;
|
||
}
|
||
CXChildVisit_Continue
|
||
});
|
||
}
|
||
CXCursor_UnexposedAttr => {
|
||
ci.found_unknown_attr = true;
|
||
}
|
||
CXCursor_EnumDecl |
|
||
CXCursor_TypeAliasDecl |
|
||
CXCursor_TypeAliasTemplateDecl |
|
||
CXCursor_TypedefDecl |
|
||
CXCursor_StructDecl |
|
||
CXCursor_UnionDecl |
|
||
CXCursor_ClassTemplate |
|
||
CXCursor_ClassDecl => {
|
||
// We can find non-semantic children here, clang uses a
|
||
// StructDecl to note incomplete structs that haven't been
|
||
// forward-declared before, see [1].
|
||
//
|
||
// Also, clang seems to scope struct definitions inside
|
||
// unions, and other named struct definitions inside other
|
||
// structs to the whole translation unit.
|
||
//
|
||
// Let's just assume that if the cursor we've found is a
|
||
// definition, it's a valid inner type.
|
||
//
|
||
// [1]: https://github.com/rust-lang/rust-bindgen/issues/482
|
||
let is_inner_struct =
|
||
cur.semantic_parent() == cursor || cur.is_definition();
|
||
if !is_inner_struct {
|
||
return CXChildVisit_Continue;
|
||
}
|
||
|
||
// Even if this is a definition, we may not be the semantic
|
||
// parent, see #1281.
|
||
let inner = Item::parse(cur, Some(potential_id), ctx)
|
||
.expect("Inner ClassDecl");
|
||
|
||
// If we avoided recursion parsing this type (in
|
||
// `Item::from_ty_with_id()`), then this might not be a
|
||
// valid type ID, so check and gracefully handle this.
|
||
if ctx.resolve_item_fallible(inner).is_some() {
|
||
let inner = inner.expect_type_id(ctx);
|
||
|
||
ci.inner_types.push(inner);
|
||
|
||
// A declaration of an union or a struct without name
|
||
// could also be an unnamed field, unfortunately.
|
||
if cur.is_anonymous() && cur.kind() != CXCursor_EnumDecl
|
||
{
|
||
let ty = cur.cur_type();
|
||
let public = cur.public_accessible();
|
||
let offset = cur.offset_of_field().ok();
|
||
|
||
maybe_anonymous_struct_field =
|
||
Some((inner, ty, public, offset));
|
||
}
|
||
}
|
||
}
|
||
CXCursor_PackedAttr => {
|
||
ci.packed_attr = true;
|
||
}
|
||
CXCursor_TemplateTypeParameter => {
|
||
let param = Item::type_param(None, cur, ctx).expect(
|
||
"Item::type_param should't fail when pointing \
|
||
at a TemplateTypeParameter",
|
||
);
|
||
ci.template_params.push(param);
|
||
}
|
||
CXCursor_CXXBaseSpecifier => {
|
||
let is_virtual_base = cur.is_virtual_base();
|
||
ci.has_own_virtual_method |= is_virtual_base;
|
||
|
||
let kind = if is_virtual_base {
|
||
BaseKind::Virtual
|
||
} else {
|
||
BaseKind::Normal
|
||
};
|
||
|
||
let field_name = match ci.base_members.len() {
|
||
0 => "_base".into(),
|
||
n => format!("_base_{}", n),
|
||
};
|
||
let type_id =
|
||
Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
|
||
ci.base_members.push(Base {
|
||
ty: type_id,
|
||
kind,
|
||
field_name,
|
||
is_pub: cur.access_specifier() ==
|
||
clang_sys::CX_CXXPublic,
|
||
});
|
||
}
|
||
CXCursor_Constructor | CXCursor_Destructor |
|
||
CXCursor_CXXMethod => {
|
||
let is_virtual = cur.method_is_virtual();
|
||
let is_static = cur.method_is_static();
|
||
debug_assert!(!(is_static && is_virtual), "How?");
|
||
|
||
ci.has_destructor |= cur.kind() == CXCursor_Destructor;
|
||
ci.has_own_virtual_method |= is_virtual;
|
||
|
||
// This used to not be here, but then I tried generating
|
||
// stylo bindings with this (without path filters), and
|
||
// cried a lot with a method in gfx/Point.h
|
||
// (ToUnknownPoint), that somehow was causing the same type
|
||
// to be inserted in the map two times.
|
||
//
|
||
// I couldn't make a reduced test case, but anyway...
|
||
// Methods of template functions not only used to be inlined,
|
||
// but also instantiated, and we wouldn't be able to call
|
||
// them, so just bail out.
|
||
if !ci.template_params.is_empty() {
|
||
return CXChildVisit_Continue;
|
||
}
|
||
|
||
// NB: This gets us an owned `Function`, not a
|
||
// `FunctionSig`.
|
||
let signature =
|
||
match Item::parse(cur, Some(potential_id), ctx) {
|
||
Ok(item)
|
||
if ctx
|
||
.resolve_item(item)
|
||
.kind()
|
||
.is_function() =>
|
||
{
|
||
item
|
||
}
|
||
_ => return CXChildVisit_Continue,
|
||
};
|
||
|
||
let signature = signature.expect_function_id(ctx);
|
||
|
||
match cur.kind() {
|
||
CXCursor_Constructor => {
|
||
ci.constructors.push(signature);
|
||
}
|
||
CXCursor_Destructor => {
|
||
let kind = if is_virtual {
|
||
MethodKind::VirtualDestructor {
|
||
pure_virtual: cur.method_is_pure_virtual(),
|
||
}
|
||
} else {
|
||
MethodKind::Destructor
|
||
};
|
||
ci.destructor = Some((kind, signature));
|
||
}
|
||
CXCursor_CXXMethod => {
|
||
let is_const = cur.method_is_const();
|
||
let method_kind = if is_static {
|
||
MethodKind::Static
|
||
} else if is_virtual {
|
||
MethodKind::Virtual {
|
||
pure_virtual: cur.method_is_pure_virtual(),
|
||
}
|
||
} else {
|
||
MethodKind::Normal
|
||
};
|
||
|
||
let method =
|
||
Method::new(method_kind, signature, is_const);
|
||
|
||
ci.methods.push(method);
|
||
}
|
||
_ => unreachable!("How can we see this here?"),
|
||
}
|
||
}
|
||
CXCursor_NonTypeTemplateParameter => {
|
||
ci.has_non_type_template_params = true;
|
||
}
|
||
CXCursor_VarDecl => {
|
||
let linkage = cur.linkage();
|
||
if linkage != CXLinkage_External &&
|
||
linkage != CXLinkage_UniqueExternal
|
||
{
|
||
return CXChildVisit_Continue;
|
||
}
|
||
|
||
let visibility = cur.visibility();
|
||
if visibility != CXVisibility_Default {
|
||
return CXChildVisit_Continue;
|
||
}
|
||
|
||
if let Ok(item) = Item::parse(cur, Some(potential_id), ctx)
|
||
{
|
||
ci.inner_vars.push(item.as_var_id_unchecked());
|
||
}
|
||
}
|
||
// Intentionally not handled
|
||
CXCursor_CXXAccessSpecifier |
|
||
CXCursor_CXXFinalAttr |
|
||
CXCursor_FunctionTemplate |
|
||
CXCursor_ConversionFunction => {}
|
||
_ => {
|
||
warn!(
|
||
"unhandled comp member `{}` (kind {:?}) in `{}` ({})",
|
||
cur.spelling(),
|
||
clang::kind_to_str(cur.kind()),
|
||
cursor.spelling(),
|
||
cur.location()
|
||
);
|
||
}
|
||
}
|
||
CXChildVisit_Continue
|
||
});
|
||
|
||
if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field {
|
||
let field =
|
||
RawField::new(None, ty, None, None, None, public, offset);
|
||
ci.fields.append_raw_field(field);
|
||
}
|
||
|
||
Ok(ci)
|
||
}
|
||
|
||
fn kind_from_cursor(
|
||
cursor: &clang::Cursor,
|
||
) -> Result<CompKind, ParseError> {
|
||
use clang_sys::*;
|
||
Ok(match cursor.kind() {
|
||
CXCursor_UnionDecl => CompKind::Union,
|
||
CXCursor_ClassDecl | CXCursor_StructDecl => CompKind::Struct,
|
||
CXCursor_CXXBaseSpecifier |
|
||
CXCursor_ClassTemplatePartialSpecialization |
|
||
CXCursor_ClassTemplate => match cursor.template_kind() {
|
||
CXCursor_UnionDecl => CompKind::Union,
|
||
_ => CompKind::Struct,
|
||
},
|
||
_ => {
|
||
warn!("Unknown kind for comp type: {:?}", cursor);
|
||
return Err(ParseError::Continue);
|
||
}
|
||
})
|
||
}
|
||
|
||
/// Get the set of types that were declared within this compound type
|
||
/// (e.g. nested class definitions).
|
||
pub(crate) fn inner_types(&self) -> &[TypeId] {
|
||
&self.inner_types
|
||
}
|
||
|
||
/// Get the set of static variables declared within this compound type.
|
||
pub(crate) 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(crate) fn found_unknown_attr(&self) -> bool {
|
||
self.found_unknown_attr
|
||
}
|
||
|
||
/// Is this compound type packed?
|
||
pub(crate) 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
|
||
}
|
||
|
||
/// Return true if a compound type is "naturally packed". This means we can exclude the
|
||
/// "packed" attribute without changing the layout.
|
||
/// This is useful for types that need an "align(N)" attribute since rustc won't compile
|
||
/// structs that have both of those attributes.
|
||
pub(crate) fn already_packed(&self, ctx: &BindgenContext) -> Option<bool> {
|
||
let mut total_size: usize = 0;
|
||
|
||
for field in self.fields().iter() {
|
||
let layout = field.layout(ctx)?;
|
||
|
||
if layout.align != 0 && total_size % layout.align != 0 {
|
||
return Some(false);
|
||
}
|
||
|
||
total_size += layout.size;
|
||
}
|
||
|
||
Some(true)
|
||
}
|
||
|
||
/// Returns true if compound type has been forward declared
|
||
pub(crate) fn is_forward_declaration(&self) -> bool {
|
||
self.is_forward_declaration
|
||
}
|
||
|
||
/// Compute this compound structure's bitfield allocation units.
|
||
pub(crate) 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(crate) 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(crate) fn is_rust_union(
|
||
&self,
|
||
ctx: &BindgenContext,
|
||
layout: Option<&Layout>,
|
||
name: &str,
|
||
) -> (bool, bool) {
|
||
if !self.is_union() {
|
||
return (false, false);
|
||
}
|
||
|
||
if !ctx.options().untagged_union {
|
||
return (false, false);
|
||
}
|
||
|
||
if self.is_forward_declaration() {
|
||
return (false, false);
|
||
}
|
||
|
||
let union_style = if ctx.options().bindgen_wrapper_union.matches(name) {
|
||
NonCopyUnionStyle::BindgenWrapper
|
||
} else if ctx.options().manually_drop_union.matches(name) {
|
||
NonCopyUnionStyle::ManuallyDrop
|
||
} else {
|
||
ctx.options().default_non_copy_union_style
|
||
};
|
||
|
||
let all_can_copy = self.fields().iter().all(|f| match *f {
|
||
Field::DataMember(ref field_data) => {
|
||
field_data.ty().can_derive_copy(ctx)
|
||
}
|
||
Field::Bitfields(_) => true,
|
||
});
|
||
|
||
if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper {
|
||
return (false, false);
|
||
}
|
||
|
||
if layout.map_or(false, |l| l.size == 0) {
|
||
return (false, false);
|
||
}
|
||
|
||
(true, all_can_copy)
|
||
}
|
||
}
|
||
|
||
impl DotAttributes for CompInfo {
|
||
fn dot_attributes<W>(
|
||
&self,
|
||
ctx: &BindgenContext,
|
||
out: &mut W,
|
||
) -> io::Result<()>
|
||
where
|
||
W: io::Write,
|
||
{
|
||
writeln!(out, "<tr><td>CompKind</td><td>{:?}</td></tr>", self.kind)?;
|
||
|
||
if self.has_own_virtual_method {
|
||
writeln!(out, "<tr><td>has_vtable</td><td>true</td></tr>")?;
|
||
}
|
||
|
||
if self.has_destructor {
|
||
writeln!(out, "<tr><td>has_destructor</td><td>true</td></tr>")?;
|
||
}
|
||
|
||
if self.has_nonempty_base {
|
||
writeln!(out, "<tr><td>has_nonempty_base</td><td>true</td></tr>")?;
|
||
}
|
||
|
||
if self.has_non_type_template_params {
|
||
writeln!(
|
||
out,
|
||
"<tr><td>has_non_type_template_params</td><td>true</td></tr>"
|
||
)?;
|
||
}
|
||
|
||
if self.packed_attr {
|
||
writeln!(out, "<tr><td>packed_attr</td><td>true</td></tr>")?;
|
||
}
|
||
|
||
if self.is_forward_declaration {
|
||
writeln!(
|
||
out,
|
||
"<tr><td>is_forward_declaration</td><td>true</td></tr>"
|
||
)?;
|
||
}
|
||
|
||
if !self.fields().is_empty() {
|
||
writeln!(out, r#"<tr><td>fields</td><td><table border="0">"#)?;
|
||
for field in self.fields() {
|
||
field.dot_attributes(ctx, out)?;
|
||
}
|
||
writeln!(out, "</table></td></tr>")?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
}
|
||
|
||
impl IsOpaque for CompInfo {
|
||
type Extra = Option<Layout>;
|
||
|
||
fn is_opaque(&self, ctx: &BindgenContext, layout: &Option<Layout>) -> bool {
|
||
if self.has_non_type_template_params ||
|
||
self.has_unevaluable_bit_field_width
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// When we do not have the layout for a bitfield's type (for example, it
|
||
// is a type parameter), then we can't compute bitfield units. We are
|
||
// left with no choice but to make the whole struct opaque, or else we
|
||
// might generate structs with incorrect sizes and alignments.
|
||
if let CompFields::Error = self.fields {
|
||
return true;
|
||
}
|
||
|
||
// Bitfields with a width that is larger than their unit's width have
|
||
// some strange things going on, and the best we can do is make the
|
||
// whole struct opaque.
|
||
if self.fields().iter().any(|f| match *f {
|
||
Field::DataMember(_) => false,
|
||
Field::Bitfields(ref unit) => unit.bitfields().iter().any(|bf| {
|
||
let bitfield_layout = ctx
|
||
.resolve_type(bf.ty())
|
||
.layout(ctx)
|
||
.expect("Bitfield without layout? Gah!");
|
||
bf.width() / 8 > bitfield_layout.size as u32
|
||
}),
|
||
}) {
|
||
return true;
|
||
}
|
||
|
||
if !ctx.options().rust_features().repr_packed_n {
|
||
// If we don't have `#[repr(packed(N)]`, the best we can
|
||
// do is make this struct opaque.
|
||
//
|
||
// See https://github.com/rust-lang/rust-bindgen/issues/537 and
|
||
// https://github.com/rust-lang/rust/issues/33158
|
||
if self.is_packed(ctx, layout.as_ref()) &&
|
||
layout.map_or(false, |l| l.align > 1)
|
||
{
|
||
warn!("Found a type that is both packed and aligned to greater than \
|
||
1; Rust before version 1.33 doesn't have `#[repr(packed(N))]`, so we \
|
||
are treating it as opaque. You may wish to set bindgen's rust target \
|
||
version to 1.33 or later to enable `#[repr(packed(N))]` support.");
|
||
return true;
|
||
}
|
||
}
|
||
|
||
false
|
||
}
|
||
}
|
||
|
||
impl TemplateParameters for CompInfo {
|
||
fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> {
|
||
self.template_params.clone()
|
||
}
|
||
}
|
||
|
||
impl Trace for CompInfo {
|
||
type Extra = Item;
|
||
|
||
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
|
||
where
|
||
T: Tracer,
|
||
{
|
||
for p in item.all_template_params(context) {
|
||
tracer.visit_kind(p.into(), EdgeKind::TemplateParameterDefinition);
|
||
}
|
||
|
||
for ty in self.inner_types() {
|
||
tracer.visit_kind(ty.into(), EdgeKind::InnerType);
|
||
}
|
||
|
||
for &var in self.inner_vars() {
|
||
tracer.visit_kind(var.into(), EdgeKind::InnerVar);
|
||
}
|
||
|
||
for method in self.methods() {
|
||
tracer.visit_kind(method.signature.into(), EdgeKind::Method);
|
||
}
|
||
|
||
if let Some((_kind, signature)) = self.destructor() {
|
||
tracer.visit_kind(signature.into(), EdgeKind::Destructor);
|
||
}
|
||
|
||
for ctor in self.constructors() {
|
||
tracer.visit_kind(ctor.into(), EdgeKind::Constructor);
|
||
}
|
||
|
||
// Base members and fields are not generated for opaque types (but all
|
||
// of the above things are) so stop here.
|
||
if item.is_opaque(context, &()) {
|
||
return;
|
||
}
|
||
|
||
for base in self.base_members() {
|
||
tracer.visit_kind(base.ty.into(), EdgeKind::BaseMember);
|
||
}
|
||
|
||
self.fields.trace(context, tracer, &());
|
||
}
|
||
}
|