1891 lines
59 KiB
Rust
1891 lines
59 KiB
Rust
|
|
//! Compound types (unions and structs) in our intermediate representation.
|
|||
|
|
|
|||
|
|
use super::analysis::Sizedness;
|
|||
|
|
use super::annotations::Annotations;
|
|||
|
|
use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
|
|||
|
|
use super::dot::DotAttributes;
|
|||
|
|
use super::item::{IsOpaque, Item};
|
|||
|
|
use super::layout::Layout;
|
|||
|
|
use super::template::TemplateParameters;
|
|||
|
|
use super::traversal::{EdgeKind, Trace, Tracer};
|
|||
|
|
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
|
|||
|
|
use crate::clang;
|
|||
|
|
use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2};
|
|||
|
|
use crate::ir::derive::CanDeriveCopy;
|
|||
|
|
use crate::parse::ParseError;
|
|||
|
|
use crate::HashMap;
|
|||
|
|
use crate::NonCopyUnionStyle;
|
|||
|
|
use peeking_take_while::PeekableExt;
|
|||
|
|
use std::cmp;
|
|||
|
|
use std::io;
|
|||
|
|
use std::mem;
|
|||
|
|
|
|||
|
|
/// The kind of compound type.
|
|||
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|||
|
|
pub enum CompKind {
|
|||
|
|
/// A struct.
|
|||
|
|
Struct,
|
|||
|
|
/// A union.
|
|||
|
|
Union,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// The kind of C++ method.
|
|||
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|||
|
|
pub enum MethodKind {
|
|||
|
|
/// A constructor. We represent it as method for convenience, to avoid code
|
|||
|
|
/// duplication.
|
|||
|
|
Constructor,
|
|||
|
|
/// A destructor.
|
|||
|
|
Destructor,
|
|||
|
|
/// A virtual destructor.
|
|||
|
|
VirtualDestructor {
|
|||
|
|
/// Whether it's pure virtual.
|
|||
|
|
pure_virtual: bool,
|
|||
|
|
},
|
|||
|
|
/// A static method.
|
|||
|
|
Static,
|
|||
|
|
/// A normal method.
|
|||
|
|
Normal,
|
|||
|
|
/// A virtual method.
|
|||
|
|
Virtual {
|
|||
|
|
/// Whether it's pure virtual.
|
|||
|
|
pure_virtual: bool,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl MethodKind {
|
|||
|
|
/// Is this a destructor method?
|
|||
|
|
pub fn is_destructor(&self) -> bool {
|
|||
|
|
matches!(
|
|||
|
|
*self,
|
|||
|
|
MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a pure virtual method?
|
|||
|
|
pub fn is_pure_virtual(&self) -> bool {
|
|||
|
|
match *self {
|
|||
|
|
MethodKind::Virtual { pure_virtual } |
|
|||
|
|
MethodKind::VirtualDestructor { pure_virtual } => pure_virtual,
|
|||
|
|
_ => false,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// A struct representing a C++ method, either static, normal, or virtual.
|
|||
|
|
#[derive(Debug)]
|
|||
|
|
pub struct Method {
|
|||
|
|
kind: MethodKind,
|
|||
|
|
/// The signature of the method. Take into account this is not a `Type`
|
|||
|
|
/// item, but a `Function` one.
|
|||
|
|
///
|
|||
|
|
/// This is tricky and probably this field should be renamed.
|
|||
|
|
signature: FunctionId,
|
|||
|
|
is_const: bool,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Method {
|
|||
|
|
/// Construct a new `Method`.
|
|||
|
|
pub fn new(
|
|||
|
|
kind: MethodKind,
|
|||
|
|
signature: FunctionId,
|
|||
|
|
is_const: bool,
|
|||
|
|
) -> Self {
|
|||
|
|
Method {
|
|||
|
|
kind,
|
|||
|
|
signature,
|
|||
|
|
is_const,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// What kind of method is this?
|
|||
|
|
pub fn kind(&self) -> MethodKind {
|
|||
|
|
self.kind
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a constructor?
|
|||
|
|
pub fn is_constructor(&self) -> bool {
|
|||
|
|
self.kind == MethodKind::Constructor
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a virtual method?
|
|||
|
|
pub fn is_virtual(&self) -> bool {
|
|||
|
|
matches!(
|
|||
|
|
self.kind,
|
|||
|
|
MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a static method?
|
|||
|
|
pub fn is_static(&self) -> bool {
|
|||
|
|
self.kind == MethodKind::Static
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the id for the `Function` signature for this method.
|
|||
|
|
pub fn signature(&self) -> FunctionId {
|
|||
|
|
self.signature
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a const qualified method?
|
|||
|
|
pub fn is_const(&self) -> bool {
|
|||
|
|
self.is_const
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Methods common to the various field types.
|
|||
|
|
pub trait FieldMethods {
|
|||
|
|
/// Get the name of this field.
|
|||
|
|
fn name(&self) -> Option<&str>;
|
|||
|
|
|
|||
|
|
/// Get the type of this field.
|
|||
|
|
fn ty(&self) -> TypeId;
|
|||
|
|
|
|||
|
|
/// Get the comment for this field.
|
|||
|
|
fn comment(&self) -> Option<&str>;
|
|||
|
|
|
|||
|
|
/// If this is a bitfield, how many bits does it need?
|
|||
|
|
fn bitfield_width(&self) -> Option<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 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 fn nth(&self) -> usize {
|
|||
|
|
self.nth
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the layout within which these bitfields reside.
|
|||
|
|
pub fn layout(&self) -> Layout {
|
|||
|
|
self.layout
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the bitfields within this unit.
|
|||
|
|
pub fn bitfields(&self) -> &[Bitfield] {
|
|||
|
|
&self.bitfields
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// A struct representing a C++ field.
|
|||
|
|
#[derive(Debug)]
|
|||
|
|
pub enum Field {
|
|||
|
|
/// A normal data member.
|
|||
|
|
DataMember(FieldData),
|
|||
|
|
|
|||
|
|
/// A physical allocation unit containing many logical bitfields.
|
|||
|
|
Bitfields(BitfieldUnit),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Field {
|
|||
|
|
/// Get this field's layout.
|
|||
|
|
pub fn layout(&self, ctx: &BindgenContext) -> Option<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 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 fn offset_into_unit(&self) -> usize {
|
|||
|
|
self.offset_into_unit
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the mask value that when &'ed with this bitfield's allocation unit
|
|||
|
|
/// produces this bitfield's value.
|
|||
|
|
pub fn mask(&self) -> u64 {
|
|||
|
|
use std::u64;
|
|||
|
|
|
|||
|
|
let unoffseted_mask =
|
|||
|
|
if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
|
|||
|
|
u64::MAX
|
|||
|
|
} else {
|
|||
|
|
(1u64 << self.width()) - 1u64
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
unoffseted_mask << self.offset_into_unit()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the bit width of this bitfield.
|
|||
|
|
pub fn width(&self) -> u32 {
|
|||
|
|
self.data.bitfield_width().unwrap()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Name of the generated Rust getter for this bitfield.
|
|||
|
|
///
|
|||
|
|
/// Panics if called before assigning bitfield accessor names or if
|
|||
|
|
/// this bitfield have no name.
|
|||
|
|
pub fn getter_name(&self) -> &str {
|
|||
|
|
assert!(
|
|||
|
|
self.name().is_some(),
|
|||
|
|
"`Bitfield::getter_name` called on anonymous field"
|
|||
|
|
);
|
|||
|
|
self.getter_name.as_ref().expect(
|
|||
|
|
"`Bitfield::getter_name` should only be called after\
|
|||
|
|
assigning bitfield accessor names",
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Name of the generated Rust setter for this bitfield.
|
|||
|
|
///
|
|||
|
|
/// Panics if called before assigning bitfield accessor names or if
|
|||
|
|
/// this bitfield have no name.
|
|||
|
|
pub fn setter_name(&self) -> &str {
|
|||
|
|
assert!(
|
|||
|
|
self.name().is_some(),
|
|||
|
|
"`Bitfield::setter_name` called on anonymous field"
|
|||
|
|
);
|
|||
|
|
self.setter_name.as_ref().expect(
|
|||
|
|
"`Bitfield::setter_name` should only be called\
|
|||
|
|
after assigning bitfield accessor names",
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl FieldMethods for Bitfield {
|
|||
|
|
fn name(&self) -> Option<&str> {
|
|||
|
|
self.data.name()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn ty(&self) -> TypeId {
|
|||
|
|
self.data.ty()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn comment(&self) -> Option<&str> {
|
|||
|
|
self.data.comment()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn bitfield_width(&self) -> Option<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 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 enum BaseKind {
|
|||
|
|
/// Normal inheritance, like:
|
|||
|
|
///
|
|||
|
|
/// ```cpp
|
|||
|
|
/// class A : public B {};
|
|||
|
|
/// ```
|
|||
|
|
Normal,
|
|||
|
|
/// Virtual inheritance, like:
|
|||
|
|
///
|
|||
|
|
/// ```cpp
|
|||
|
|
/// class A: public virtual B {};
|
|||
|
|
/// ```
|
|||
|
|
Virtual,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// A base class.
|
|||
|
|
#[derive(Clone, Debug)]
|
|||
|
|
pub struct Base {
|
|||
|
|
/// The type of this base class.
|
|||
|
|
pub ty: TypeId,
|
|||
|
|
/// The kind of inheritance we're doing.
|
|||
|
|
pub kind: BaseKind,
|
|||
|
|
/// Name of the field in which this base should be stored.
|
|||
|
|
pub field_name: String,
|
|||
|
|
/// Whether this base is inherited from publically.
|
|||
|
|
pub is_pub: bool,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Base {
|
|||
|
|
/// Whether this base class is inheriting virtually.
|
|||
|
|
pub fn is_virtual(&self) -> bool {
|
|||
|
|
self.kind == BaseKind::Virtual
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Whether this base class should have it's own field for storage.
|
|||
|
|
pub fn requires_storage(&self, ctx: &BindgenContext) -> bool {
|
|||
|
|
// Virtual bases are already taken into account by the vtable
|
|||
|
|
// pointer.
|
|||
|
|
//
|
|||
|
|
// FIXME(emilio): Is this always right?
|
|||
|
|
if self.is_virtual() {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NB: We won't include zero-sized types in our base chain because they
|
|||
|
|
// would contribute to our size given the dummy field we insert for
|
|||
|
|
// zero-sized types.
|
|||
|
|
if self.ty.is_zero_sized(ctx) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Whether this base is inherited from publically.
|
|||
|
|
pub fn is_public(&self) -> bool {
|
|||
|
|
self.is_pub
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// A compound type.
|
|||
|
|
///
|
|||
|
|
/// Either a struct or union, a compound type is built up from the combination
|
|||
|
|
/// of fields which also are associated with their own (potentially compound)
|
|||
|
|
/// type.
|
|||
|
|
#[derive(Debug)]
|
|||
|
|
pub struct CompInfo {
|
|||
|
|
/// Whether this is a struct or a union.
|
|||
|
|
kind: CompKind,
|
|||
|
|
|
|||
|
|
/// The members of this struct or union.
|
|||
|
|
fields: CompFields,
|
|||
|
|
|
|||
|
|
/// The abstract template parameters of this class. Note that these are NOT
|
|||
|
|
/// concrete template arguments, and should always be a
|
|||
|
|
/// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see
|
|||
|
|
/// `TypeKind::TemplateInstantiation`.
|
|||
|
|
template_params: Vec<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 fn new(kind: CompKind) -> Self {
|
|||
|
|
CompInfo {
|
|||
|
|
kind,
|
|||
|
|
fields: CompFields::default(),
|
|||
|
|
template_params: vec![],
|
|||
|
|
methods: vec![],
|
|||
|
|
constructors: vec![],
|
|||
|
|
destructor: None,
|
|||
|
|
base_members: vec![],
|
|||
|
|
inner_types: vec![],
|
|||
|
|
inner_vars: vec![],
|
|||
|
|
has_own_virtual_method: false,
|
|||
|
|
has_destructor: false,
|
|||
|
|
has_nonempty_base: false,
|
|||
|
|
has_non_type_template_params: false,
|
|||
|
|
has_unevaluable_bit_field_width: false,
|
|||
|
|
packed_attr: false,
|
|||
|
|
found_unknown_attr: false,
|
|||
|
|
is_forward_declaration: false,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Compute the layout of this type.
|
|||
|
|
///
|
|||
|
|
/// This is called as a fallback under some circumstances where LLVM doesn't
|
|||
|
|
/// give us the correct layout.
|
|||
|
|
///
|
|||
|
|
/// If we're a union without known layout, we try to compute it from our
|
|||
|
|
/// members. This is not ideal, but clang fails to report the size for these
|
|||
|
|
/// kind of unions, see test/headers/template_union.hpp
|
|||
|
|
pub fn layout(&self, ctx: &BindgenContext) -> Option<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 fn fields(&self) -> &[Field] {
|
|||
|
|
match self.fields {
|
|||
|
|
CompFields::Error => &[],
|
|||
|
|
CompFields::After { ref fields, .. } => fields,
|
|||
|
|
CompFields::Before(..) => {
|
|||
|
|
panic!("Should always have computed bitfield units first");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn has_fields(&self) -> bool {
|
|||
|
|
match self.fields {
|
|||
|
|
CompFields::Error => false,
|
|||
|
|
CompFields::After { ref fields, .. } => !fields.is_empty(),
|
|||
|
|
CompFields::Before(ref raw_fields) => !raw_fields.is_empty(),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn each_known_field_layout(
|
|||
|
|
&self,
|
|||
|
|
ctx: &BindgenContext,
|
|||
|
|
mut callback: impl FnMut(Layout),
|
|||
|
|
) {
|
|||
|
|
match self.fields {
|
|||
|
|
CompFields::Error => {}
|
|||
|
|
CompFields::After { ref fields, .. } => {
|
|||
|
|
for field in fields.iter() {
|
|||
|
|
if let Some(layout) = field.layout(ctx) {
|
|||
|
|
callback(layout);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
CompFields::Before(ref raw_fields) => {
|
|||
|
|
for field in raw_fields.iter() {
|
|||
|
|
let field_ty = ctx.resolve_type(field.0.ty);
|
|||
|
|
if let Some(layout) = field_ty.layout(ctx) {
|
|||
|
|
callback(layout);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn has_bitfields(&self) -> bool {
|
|||
|
|
match self.fields {
|
|||
|
|
CompFields::Error => false,
|
|||
|
|
CompFields::After {
|
|||
|
|
has_bitfield_units, ..
|
|||
|
|
} => has_bitfield_units,
|
|||
|
|
CompFields::Before(_) => {
|
|||
|
|
panic!("Should always have computed bitfield units first");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Returns whether we have a too large bitfield unit, in which case we may
|
|||
|
|
/// not be able to derive some of the things we should be able to normally
|
|||
|
|
/// derive.
|
|||
|
|
pub fn has_too_large_bitfield_unit(&self) -> bool {
|
|||
|
|
if !self.has_bitfields() {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
self.fields().iter().any(|field| match *field {
|
|||
|
|
Field::DataMember(..) => false,
|
|||
|
|
Field::Bitfields(ref unit) => {
|
|||
|
|
unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Does this type have any template parameters that aren't types
|
|||
|
|
/// (e.g. int)?
|
|||
|
|
pub fn has_non_type_template_params(&self) -> bool {
|
|||
|
|
self.has_non_type_template_params
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Do we see a virtual function during parsing?
|
|||
|
|
/// Get the has_own_virtual_method boolean.
|
|||
|
|
pub fn has_own_virtual_method(&self) -> bool {
|
|||
|
|
self.has_own_virtual_method
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Did we see a destructor when parsing this type?
|
|||
|
|
pub fn has_own_destructor(&self) -> bool {
|
|||
|
|
self.has_destructor
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get this type's set of methods.
|
|||
|
|
pub fn methods(&self) -> &[Method] {
|
|||
|
|
&self.methods
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get this type's set of constructors.
|
|||
|
|
pub fn constructors(&self) -> &[FunctionId] {
|
|||
|
|
&self.constructors
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get this type's destructor.
|
|||
|
|
pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
|
|||
|
|
self.destructor
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// What kind of compound type is this?
|
|||
|
|
pub fn kind(&self) -> CompKind {
|
|||
|
|
self.kind
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this a union?
|
|||
|
|
pub fn is_union(&self) -> bool {
|
|||
|
|
self.kind() == CompKind::Union
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// The set of types that this one inherits from.
|
|||
|
|
pub fn base_members(&self) -> &[Base] {
|
|||
|
|
&self.base_members
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Construct a new compound type from a Clang type.
|
|||
|
|
pub fn from_ty(
|
|||
|
|
potential_id: ItemId,
|
|||
|
|
ty: &clang::Type,
|
|||
|
|
location: Option<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 fn inner_types(&self) -> &[TypeId] {
|
|||
|
|
&self.inner_types
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Get the set of static variables declared within this compound type.
|
|||
|
|
pub fn inner_vars(&self) -> &[VarId] {
|
|||
|
|
&self.inner_vars
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Have we found a field with an opaque type that could potentially mess up
|
|||
|
|
/// the layout of this compound type?
|
|||
|
|
pub fn found_unknown_attr(&self) -> bool {
|
|||
|
|
self.found_unknown_attr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Is this compound type packed?
|
|||
|
|
pub fn is_packed(
|
|||
|
|
&self,
|
|||
|
|
ctx: &BindgenContext,
|
|||
|
|
layout: Option<&Layout>,
|
|||
|
|
) -> bool {
|
|||
|
|
if self.packed_attr {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Even though `libclang` doesn't expose `#pragma packed(...)`, we can
|
|||
|
|
// detect it through its effects.
|
|||
|
|
if let Some(parent_layout) = layout {
|
|||
|
|
let mut packed = false;
|
|||
|
|
self.each_known_field_layout(ctx, |layout| {
|
|||
|
|
packed = packed || layout.align > parent_layout.align;
|
|||
|
|
});
|
|||
|
|
if packed {
|
|||
|
|
info!("Found a struct that was defined within `#pragma packed(...)`");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if self.has_own_virtual_method && parent_layout.align == 1 {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Returns true if compound type has been forward declared
|
|||
|
|
pub fn is_forward_declaration(&self) -> bool {
|
|||
|
|
self.is_forward_declaration
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Compute this compound structure's bitfield allocation units.
|
|||
|
|
pub fn compute_bitfield_units(
|
|||
|
|
&mut self,
|
|||
|
|
ctx: &BindgenContext,
|
|||
|
|
layout: Option<&Layout>,
|
|||
|
|
) {
|
|||
|
|
let packed = self.is_packed(ctx, layout);
|
|||
|
|
self.fields.compute_bitfield_units(ctx, packed)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Assign for each anonymous field a generated name.
|
|||
|
|
pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) {
|
|||
|
|
self.fields.deanonymize_fields(ctx, &self.methods);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Returns whether the current union can be represented as a Rust `union`
|
|||
|
|
///
|
|||
|
|
/// Requirements:
|
|||
|
|
/// 1. Current RustTarget allows for `untagged_union`
|
|||
|
|
/// 2. Each field can derive `Copy` or we use ManuallyDrop.
|
|||
|
|
/// 3. It's not zero-sized.
|
|||
|
|
///
|
|||
|
|
/// Second boolean returns whether all fields can be copied (and thus
|
|||
|
|
/// ManuallyDrop is not needed).
|
|||
|
|
pub fn is_rust_union(
|
|||
|
|
&self,
|
|||
|
|
ctx: &BindgenContext,
|
|||
|
|
layout: Option<&Layout>,
|
|||
|
|
name: &str,
|
|||
|
|
) -> (bool, bool) {
|
|||
|
|
if !self.is_union() {
|
|||
|
|
return (false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if !ctx.options().rust_features().untagged_union {
|
|||
|
|
return (false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if self.is_forward_declaration() {
|
|||
|
|
return (false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let union_style = if ctx.options().bindgen_wrapper_union.matches(name) {
|
|||
|
|
NonCopyUnionStyle::BindgenWrapper
|
|||
|
|
} else if ctx.options().manually_drop_union.matches(name) {
|
|||
|
|
NonCopyUnionStyle::ManuallyDrop
|
|||
|
|
} else {
|
|||
|
|
ctx.options().default_non_copy_union_style
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
let all_can_copy = self.fields().iter().all(|f| match *f {
|
|||
|
|
Field::DataMember(ref field_data) => {
|
|||
|
|
field_data.ty().can_derive_copy(ctx)
|
|||
|
|
}
|
|||
|
|
Field::Bitfields(_) => true,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper {
|
|||
|
|
return (false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if layout.map_or(false, |l| l.size == 0) {
|
|||
|
|
return (false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
(true, all_can_copy)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl DotAttributes for CompInfo {
|
|||
|
|
fn dot_attributes<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, &());
|
|||
|
|
}
|
|||
|
|
}
|