//! Compound types (unions and structs) in our intermediate representation.
use itertools::Itertools;
usesuper::analysis::Sizedness; usesuper::annotations::Annotations; usesuper::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId}; usesuper::dot::DotAttributes; usesuper::item::{IsOpaque, Item}; usesuper::layout::Layout; usesuper::template::TemplateParameters; usesuper::traversal::{EdgeKind, Trace, Tracer}; usesuper::ty::RUST_DERIVE_IN_ARRAY_LIMIT; usecrate::clang; usecrate::codegen::struct_layout::{align_to, bytes_from_bits_pow2}; usecrate::ir::derive::CanDeriveCopy; usecrate::parse::ParseError; usecrate::HashMap; usecrate::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,
}
/// 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)
}
}
}
}
/// 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());
/// 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",
)
}
}
/// 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);
/// 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>,
{ letmut raw_fields = raw_fields.into_iter().fuse().peekable(); letmut fields = vec![]; letmut 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. letmut bitfields = raw_fields
.by_ref()
.peeking_take_while(|f| f.bitfield_width().is_some())
.peekable();
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,
})));
}
// 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;
letmut 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;
}
} elseif 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,
}
letmut anon_field_counter = 0; for field in fields.iter_mut() { match *field {
Field::DataMember(FieldData { refmut name, .. }) => { if name.is_some() { continue;
}
anon_field_counter += 1;
*name = Some(format!( "{}{}",
ctx.options().anon_fields_prefix,
anon_field_counter
));
}
Field::Bitfields(refmut bu) => { for bitfield in &mut bu.bitfields { if bitfield.name().is_none() { continue;
}
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>,
}
/// 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? ifself.is_virtual() { returnfalse;
}
// 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. ifself.ty.is_zero_sized(ctx) { returnfalse;
}
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,
}
/// 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. ifself.kind == CompKind::Struct { return None;
}
// By definition, we don't have the right layout information here if // we're a forward declaration. ifself.is_forward_declaration() { return None;
}
// empty union case if !self.has_fields() { return None;
}
/// 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() { returnfalse;
} 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"
);
letmut maybe_anonymous_struct_field = None;
cursor.visit(|cur| { if cur.kind() != CXCursor_FieldDecl { iflet 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 => { iflet Some((ty, clang_ty, public, offset)) =
maybe_anonymous_struct_field.take()
{ letmut 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?");
// 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
} elseif 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;
}
/// 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 { ifself.packed_attr { returntrue;
}
// Even though `libclang` doesn't expose `#pragma packed(...)`, we can // detect it through its effects. iflet Some(parent_layout) = layout { letmut 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(...)`"); returntrue;
}
/// 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> { letmut total_size: usize = 0;
for field inself.fields().iter() { let layout = field.layout(ctx)?;
/// Assign for each anonymous field a generated name. pub(crate) fn deanonymize_fields(&mutself, 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);
}
// 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. iflet CompFields::Error = self.fields { returntrue;
}
// 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. ifself.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
}),
}) { returntrue;
}
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 ifself.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."); returntrue;
}
}
for ctor inself.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 inself.base_members() {
tracer.visit_kind(base.ty.into(), EdgeKind::BaseMember);
}
self.fields.trace(context, tracer, &());
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.