summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlier Lu <flier.lu@gmail.com>2017-02-02 01:02:39 +0800
committerFlier Lu <flier.lu@nexusguard.com>2017-02-07 10:55:50 +0800
commit7fd707004b03a8110c6d82e82165f9e1a8ad6985 (patch)
tree94b170597b30a470edde2c6999a6e2a52e3db9c2 /src
parent7fa654c699b61250787e53a300357f0c58c55b18 (diff)
add padding bytes to align strcture
Diffstat (limited to 'src')
-rw-r--r--src/clang.rs11
-rw-r--r--src/codegen/mod.rs119
-rw-r--r--src/codegen/struct_layout.rs193
-rw-r--r--src/ir/comp.rs138
-rw-r--r--src/ir/enum_ty.rs15
-rw-r--r--src/ir/ty.rs50
6 files changed, 465 insertions, 61 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 4a46b694..ffe9d5d0 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -499,6 +499,17 @@ impl Cursor {
unsafe { clang_CXXField_isMutable(self.x) != 0 }
}
+ /// Get the offset of the field represented by the Cursor.
+ pub fn offset_of_field(&self) -> Result<usize, LayoutError> {
+ let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) };
+
+ if offset < 0 {
+ Err(LayoutError::from(offset as i32))
+ } else {
+ Ok(offset as usize)
+ }
+ }
+
/// Is this cursor's referent a member function that is declared `static`?
pub fn method_is_static(&self) -> bool {
unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 3b0882af..f4da014e 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1,6 +1,8 @@
mod helpers;
+mod struct_layout;
use self::helpers::{BlobTyBuilder, attributes};
+use self::struct_layout::StructLayoutTracker;
use aster;
use ir::annotations::FieldAccessorKind;
@@ -21,6 +23,7 @@ use ir::var::Var;
use std::borrow::Cow;
use std::cell::Cell;
+use std::cmp;
use std::collections::{HashSet, VecDeque};
use std::collections::hash_map::{Entry, HashMap};
use std::fmt::Write;
@@ -723,9 +726,9 @@ impl<'a> Bitfield<'a> {
fn codegen_fields(self,
ctx: &BindgenContext,
fields: &mut Vec<ast::StructField>,
- methods: &mut Vec<ast::ImplItem>) {
+ methods: &mut Vec<ast::ImplItem>)
+ -> Layout {
use aster::struct_field::StructFieldBuilder;
- use std::cmp;
let mut total_width = self.fields
.iter()
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
@@ -736,10 +739,9 @@ impl<'a> Bitfield<'a> {
debug_assert_eq!(total_width % 8, 0);
let total_width_in_bytes = total_width as usize / 8;
- let bitfield_type =
- BlobTyBuilder::new(Layout::new(total_width_in_bytes,
- total_width_in_bytes))
- .build();
+ let bitfield_layout = Layout::new(total_width_in_bytes,
+ total_width_in_bytes);
+ let bitfield_type = BlobTyBuilder::new(bitfield_layout).build();
let field_name = format!("_bitfield_{}", self.index);
let field_ident = ctx.ext_cx().ident_of(&field_name);
let field = StructFieldBuilder::named(&field_name)
@@ -805,6 +807,8 @@ impl<'a> Bitfield<'a> {
methods.extend(items.into_iter());
offset += width;
}
+
+ bitfield_layout
}
}
@@ -940,6 +944,7 @@ impl CodeGenerator for CompInfo {
// Also, we need to generate the vtable in such a way it "inherits" from
// the parent too.
let mut fields = vec![];
+ let mut struct_layout = StructLayoutTracker::new(ctx, self);
if self.needs_explicit_vtable(ctx) {
let vtable =
Vtable::new(item.id(), self.methods(), self.base_members());
@@ -951,6 +956,8 @@ impl CodeGenerator for CompInfo {
.pub_()
.build_ty(vtable_type);
+ struct_layout.saw_vtable();
+
fields.push(vtable_field);
}
@@ -985,6 +992,8 @@ impl CodeGenerator for CompInfo {
format!("_base_{}", i)
};
+ struct_layout.saw_base(base_ty);
+
let field = StructFieldBuilder::named(field_name)
.pub_()
.build_ty(inner);
@@ -1039,8 +1048,12 @@ impl CodeGenerator for CompInfo {
let bitfield_fields =
mem::replace(&mut current_bitfield_fields, vec![]);
bitfield_count += 1;
- Bitfield::new(bitfield_count, bitfield_fields)
+ let bitfield_layout = Bitfield::new(bitfield_count,
+ bitfield_fields)
.codegen_fields(ctx, &mut fields, &mut methods);
+
+ struct_layout.saw_bitfield(bitfield_layout);
+
current_bitfield_width = None;
current_bitfield_layout = None;
}
@@ -1100,6 +1113,11 @@ impl CodeGenerator for CompInfo {
}
};
+ if let Some(padding_field) =
+ struct_layout.pad_field(&field_name, field_ty, field.offset()) {
+ fields.push(padding_field);
+ }
+
let is_private = field.annotations()
.private_fields()
.unwrap_or(fields_should_be_private);
@@ -1192,8 +1210,11 @@ impl CodeGenerator for CompInfo {
let bitfield_fields = mem::replace(&mut current_bitfield_fields,
vec![]);
bitfield_count += 1;
- Bitfield::new(bitfield_count, bitfield_fields)
+ let bitfield_layout = Bitfield::new(bitfield_count,
+ bitfield_fields)
.codegen_fields(ctx, &mut fields, &mut methods);
+
+ struct_layout.saw_bitfield(bitfield_layout);
}
debug_assert!(current_bitfield_fields.is_empty());
@@ -1203,6 +1224,9 @@ impl CodeGenerator for CompInfo {
let field = StructFieldBuilder::named("bindgen_union_field")
.pub_()
.build_ty(ty);
+
+ struct_layout.saw_union(layout);
+
fields.push(field);
}
@@ -1227,6 +1251,16 @@ impl CodeGenerator for CompInfo {
warn!("Opaque type without layout! Expect dragons!");
}
}
+ } else if !is_union && !self.is_unsized(ctx) {
+ if let Some(padding_field) =
+ layout.and_then(|layout| struct_layout.pad_struct(layout)) {
+ fields.push(padding_field);
+ }
+
+ if let Some(align_field) =
+ layout.and_then(|layout| struct_layout.align_struct(layout)) {
+ fields.push(align_field);
+ }
}
// C requires every struct to be addressable, so what C compilers do is
@@ -1296,7 +1330,7 @@ impl CodeGenerator for CompInfo {
canonical_name);
}
- if applicable_template_args.is_empty() && !self.found_unknown_attr() {
+ if applicable_template_args.is_empty() {
for var in self.inner_vars() {
ctx.resolve_item(*var)
.codegen(ctx, result, whitelisted_items, &());
@@ -1313,11 +1347,57 @@ impl CodeGenerator for CompInfo {
::$prefix::mem::align_of::<$ident>());
let size = layout.size;
let align = layout.align;
+
+ let check_struct_align = if align > mem::size_of::<*mut ()>() {
+ // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready
+ None
+ } else {
+ quote_item!(ctx.ext_cx(),
+ assert_eq!($align_of_expr, $align);
+ )
+ };
+
+ // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready
+ let too_many_base_vtables = self.base_members()
+ .iter()
+ .filter(|base| ctx.resolve_type(base.ty).has_vtable(ctx))
+ .count() >
+ 1;
+
+ let should_skip_field_offset_checks = item.is_opaque(ctx) ||
+ too_many_base_vtables;
+
+ let check_field_offset = if should_skip_field_offset_checks {
+ None
+ } else {
+ let type_name = ctx.rust_ident(&canonical_name);
+
+ let asserts = self.fields()
+ .iter()
+ .filter(|field| field.bitfield().is_none())
+ .flat_map(|field| {
+ field.name().and_then(|name| {
+ field.offset().and_then(|offset| {
+ let field_offset = offset / 8;
+ let field_name = ctx.rust_ident(name);
+
+ quote_item!(ctx.ext_cx(),
+ assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, $field_offset);
+ )
+ })
+ })
+ }).collect::<Vec<P<ast::Item>>>();
+
+ Some(asserts)
+ };
+
let item = quote_item!(ctx.ext_cx(),
#[test]
fn $fn_name() {
assert_eq!($size_of_expr, $size);
- assert_eq!($align_of_expr, $align);
+
+ $check_struct_align
+ $check_field_offset
})
.unwrap();
result.push(item);
@@ -2278,22 +2358,20 @@ impl CodeGenerator for ObjCInterface {
// Collect the actual used argument names
let arg_names: Vec<_> = fn_args.iter()
- .map(|ref arg| {
- match arg.pat.node {
- ast::PatKind::Ident(_, ref spanning, _) => {
- spanning.node.name.as_str().to_string()
- }
- _ => {
- panic!("odd argument!");
- }
+ .map(|ref arg| match arg.pat.node {
+ ast::PatKind::Ident(_, ref spanning, _) => {
+ spanning.node.name.as_str().to_string()
+ }
+ _ => {
+ panic!("odd argument!");
}
})
.collect();
let methods_and_args =
ctx.rust_ident(&method.format_method_call(&arg_names));
- let body =
- quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
+ let body = quote_stmt!(ctx.ext_cx(),
+ msg_send![self, $methods_and_args])
.unwrap();
let block = ast::Block {
stmts: vec![body],
@@ -2729,5 +2807,4 @@ mod utils {
}
}).collect::<Vec<_>>()
}
-
}
diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs
new file mode 100644
index 00000000..3006a31a
--- /dev/null
+++ b/src/codegen/struct_layout.rs
@@ -0,0 +1,193 @@
+//! Helpers for code generation that need struct layout
+
+use super::helpers::BlobTyBuilder;
+
+use aster::struct_field::StructFieldBuilder;
+
+use ir::comp::CompInfo;
+use ir::context::BindgenContext;
+use ir::layout::Layout;
+use ir::ty::Type;
+use std::cmp;
+use std::mem;
+
+use syntax::ast;
+
+/// Trace the layout of struct.
+pub struct StructLayoutTracker<'a, 'ctx: 'a> {
+ ctx: &'a BindgenContext<'ctx>,
+ comp: &'a CompInfo,
+ latest_offset: usize,
+ padding_count: usize,
+ latest_field_layout: Option<Layout>,
+ max_field_align: usize,
+}
+
+impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
+ pub fn new(ctx: &'a BindgenContext<'ctx>, comp: &'a CompInfo) -> Self {
+ StructLayoutTracker {
+ ctx: ctx,
+ comp: comp,
+ latest_offset: 0,
+ padding_count: 0,
+ latest_field_layout: None,
+ max_field_align: 0,
+ }
+ }
+
+ pub fn saw_vtable(&mut self) {
+ let ptr_size = mem::size_of::<*mut ()>();
+ self.latest_offset += ptr_size;
+ self.latest_field_layout = Some(Layout::new(ptr_size, ptr_size));
+ self.max_field_align = ptr_size;
+ }
+
+ pub fn saw_base(&mut self, base_ty: &Type) {
+ self.align_to_latest_field();
+
+ if let Some(layout) = base_ty.layout(self.ctx) {
+ self.latest_offset += self.padding_bytes(layout) + layout.size;
+ self.latest_field_layout = Some(layout);
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ }
+ }
+
+ pub fn saw_bitfield(&mut self, layout: Layout) {
+ self.align_to_latest_field();
+
+ self.latest_offset += self.padding_bytes(layout) + layout.size;
+ self.latest_field_layout = Some(layout);
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ }
+
+ pub fn saw_union(&mut self, layout: Layout) {
+ self.align_to_latest_field();
+
+ self.latest_offset += self.padding_bytes(layout) + layout.size;
+ self.latest_field_layout = Some(layout);
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ }
+
+ pub fn pad_field(&mut self,
+ field_name: &str,
+ field_ty: &Type,
+ field_offset: Option<usize>)
+ -> Option<ast::StructField> {
+ field_ty.layout(self.ctx).and_then(|field_layout| {
+ self.align_to_latest_field();
+
+ let padding_layout = if self.comp.packed() {
+ None
+ } else {
+ let calculated_layout = field_ty.as_comp()
+ .and_then(|comp| comp.calc_layout(self.ctx))
+ .unwrap_or(field_layout);
+
+ let align = cmp::min(calculated_layout.align, mem::size_of::<*mut ()>());
+
+ let (padding_bytes, need_padding) = match field_offset {
+ Some(offset) if offset / 8 > self.latest_offset => {
+ (offset / 8 - self.latest_offset, true)
+ }
+ _ => {
+ (self.padding_bytes(field_layout), (self.latest_offset % field_layout.align) != 0)
+ }
+ };
+
+ self.latest_offset += padding_bytes;
+
+ debug!("align field {} to {}/{} with {} padding bytes {:?}, calculated {:?}",
+ field_name,
+ self.latest_offset,
+ field_offset.unwrap_or(0) / 8,
+ padding_bytes,
+ field_layout,
+ calculated_layout);
+
+ if need_padding &&
+ (padding_bytes > calculated_layout.align ||
+ field_layout.align > mem::size_of::<*mut ()>()) {
+ Some(Layout::new(padding_bytes, align))
+ } else {
+ None
+ }
+ };
+
+ self.latest_offset += field_ty.calc_size(self.ctx).unwrap_or(field_layout.size);
+
+ self.latest_field_layout = Some(field_layout);
+ self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
+
+ padding_layout.map(|layout| self.padding_field(layout))
+ })
+ }
+
+ pub fn pad_struct(&mut self, layout: Layout) -> Option<ast::StructField> {
+ if layout.size < self.latest_offset {
+ warn!("calculate struct layout incorrect, too more {} bytes",
+ self.latest_offset - layout.size);
+
+ None
+ } else {
+ let padding_bytes = layout.size - self.latest_offset;
+ let struct_align = cmp::min(layout.align,
+ mem::size_of::<*mut ()>());
+
+ if padding_bytes > struct_align ||
+ (layout.align > mem::size_of::<*mut ()>() && padding_bytes > 0) {
+ let padding_align = if self.comp.packed() {
+ 1
+ } else {
+ cmp::min(1 << padding_bytes.trailing_zeros(),
+ mem::size_of::<*mut ()>())
+ };
+
+ Some(self.padding_field(Layout::new(padding_bytes, padding_align)))
+ } else {
+ None
+ }
+ }
+ }
+
+ pub fn align_struct(&self, layout: Layout) -> Option<ast::StructField> {
+ if self.max_field_align < layout.align &&
+ layout.align <= mem::size_of::<*mut ()>() {
+ let ty = BlobTyBuilder::new(Layout::new(0, layout.align)).build();
+
+ Some(StructFieldBuilder::named("__bindgen_align")
+ .pub_()
+ .build_ty(ty))
+ } else {
+ None
+ }
+ }
+
+ fn padding_bytes(&self, layout: Layout) -> usize {
+ if self.latest_offset % layout.align == 0 {
+ 0
+ } else {
+ layout.align - (self.latest_offset % layout.align)
+ }
+ }
+
+ fn padding_field(&mut self, layout: Layout) -> ast::StructField {
+ let ty = BlobTyBuilder::new(layout).build();
+ let padding_count = self.padding_count;
+
+ self.padding_count += 1;
+
+ let padding_field_name = format!("__bindgen_padding_{}", padding_count);
+
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+
+ StructFieldBuilder::named(padding_field_name).pub_().build_ty(ty)
+ }
+
+ fn align_to_latest_field(&mut self) {
+ if self.comp.packed() {
+ // skip to align field when packed
+ } else if let Some(layout) = self.latest_field_layout {
+ self.latest_offset += self.padding_bytes(layout);
+ }
+ }
+}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 34bd7a54..53efd278 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -102,6 +102,8 @@ pub struct Field {
bitfield: Option<u32>,
/// If the C++ field is marked as `mutable`
mutable: bool,
+ /// The offset of the field (in bits)
+ offset: Option<usize>,
}
impl Field {
@@ -111,7 +113,8 @@ impl Field {
comment: Option<String>,
annotations: Option<Annotations>,
bitfield: Option<u32>,
- mutable: bool)
+ mutable: bool,
+ offset: Option<usize>)
-> Field {
Field {
name: name,
@@ -120,6 +123,7 @@ impl Field {
annotations: annotations.unwrap_or_default(),
bitfield: bitfield,
mutable: mutable,
+ offset: offset,
}
}
@@ -152,6 +156,11 @@ impl Field {
pub fn annotations(&self) -> &Annotations {
&self.annotations
}
+
+ /// The offset of the field (in bits)
+ pub fn offset(&self) -> Option<usize> {
+ self.offset
+ }
}
impl CanDeriveDebug for Field {
@@ -390,26 +399,73 @@ impl CompInfo {
/// members. This is not ideal, but clang fails to report the size for these
/// kind of unions, see test/headers/template_union.hpp
pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
- use std::cmp;
-
// We can't do better than clang here, sorry.
if self.kind == CompKind::Struct {
- return None;
+ None
+ } else {
+ self.calc_layout(ctx)
}
+ }
+
+ /// Compute the layout of this type.
+ pub fn calc_layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ use std::cmp;
+ use std::mem;
- let mut max_size = 0;
- let mut max_align = 0;
- for field in &self.fields {
- let field_layout = ctx.resolve_type(field.ty)
- .layout(ctx);
+ if self.kind == CompKind::Struct {
+ let mut latest_offset_in_bits = 0;
+ let mut max_align = 0;
- if let Some(layout) = field_layout {
- max_size = cmp::max(max_size, layout.size);
- max_align = cmp::max(max_align, layout.align);
+ if self.needs_explicit_vtable(ctx) {
+ latest_offset_in_bits += mem::size_of::<*mut ()>() * 8;
+ max_align = mem::size_of::<*mut ()>();
}
- }
- Some(Layout::new(max_size, max_align))
+ for field in &self.fields {
+ if let Some(bits) = field.bitfield() {
+ latest_offset_in_bits += bits as usize;
+ } else {
+ let field_ty = ctx.resolve_type(field.ty);
+
+ if let Some(field_layout) =
+ field_ty.as_comp()
+ .and_then(|comp| comp.calc_layout(ctx))
+ .or_else(|| field_ty.layout(ctx)) {
+
+ let n = (latest_offset_in_bits / 8) %
+ field_layout.align;
+
+ if !self.packed && n != 0 {
+ latest_offset_in_bits += (field_layout.align - n) *
+ 8;
+ }
+
+ latest_offset_in_bits += field_layout.size * 8;
+ max_align = cmp::max(max_align, field_layout.align);
+ }
+ }
+ }
+
+ if latest_offset_in_bits == 0 && max_align == 0 {
+ None
+ } else {
+ Some(Layout::new((latest_offset_in_bits + 7) / 8, max_align))
+ }
+ } else {
+ let mut max_size = 0;
+ let mut max_align = 0;
+ for field in &self.fields {
+ let field_layout = ctx.resolve_type(field.ty)
+ .layout(ctx);
+
+ if let Some(layout) = field_layout {
+ max_size = cmp::max(max_size, layout.size);
+ max_align = cmp::max(max_align, layout.align);
+ }
+ }
+
+ Some(Layout::new(max_size, max_align))
+ }
}
/// Get this type's set of fields.
@@ -529,35 +585,35 @@ impl CompInfo {
let mut maybe_anonymous_struct_field = None;
cursor.visit(|cur| {
if cur.kind() != CXCursor_FieldDecl {
- if let Some((ty, _)) = maybe_anonymous_struct_field {
- let field = Field::new(None, ty, None, None, None, false);
+ if let Some((ty, _, offset)) =
+ maybe_anonymous_struct_field.take() {
+ let field =
+ Field::new(None, ty, None, None, None, false, offset);
ci.fields.push(field);
}
- maybe_anonymous_struct_field = None;
}
match cur.kind() {
CXCursor_FieldDecl => {
- match maybe_anonymous_struct_field.take() {
- Some((ty, clang_ty)) => {
- let mut used = false;
- cur.visit(|child| {
- if child.cur_type() == clang_ty {
- used = true;
- }
- CXChildVisit_Continue
- });
- if !used {
- let field = Field::new(None,
- ty,
- None,
- None,
- None,
- false);
- ci.fields.push(field);
+ if let Some((ty, clang_ty, offset)) =
+ maybe_anonymous_struct_field.take() {
+ let mut used = false;
+ cur.visit(|child| {
+ if child.cur_type() == clang_ty {
+ used = true;
}
+ CXChildVisit_Continue
+ });
+ if !used {
+ let field = Field::new(None,
+ ty,
+ None,
+ None,
+ None,
+ false,
+ offset);
+ ci.fields.push(field);
}
- None => {}
}
let bit_width = cur.bit_width();
@@ -570,6 +626,7 @@ impl CompInfo {
let annotations = Annotations::new(&cur);
let name = cur.spelling();
let is_mutable = cursor.is_mutable_field();
+ let offset = cur.offset_of_field().ok();
// Name can be empty if there are bitfields, for example,
// see tests/headers/struct_with_bitfields.h
@@ -583,7 +640,8 @@ impl CompInfo {
comment,
annotations,
bit_width,
- is_mutable);
+ is_mutable,
+ offset);
ci.fields.push(field);
// No we look for things like attributes and stuff.
@@ -615,7 +673,9 @@ impl CompInfo {
if cur.spelling().is_empty() &&
cur.kind() != CXCursor_EnumDecl {
let ty = cur.cur_type();
- maybe_anonymous_struct_field = Some((inner, ty));
+ let offset = cur.offset_of_field().ok();
+ maybe_anonymous_struct_field =
+ Some((inner, ty, offset));
}
}
CXCursor_PackedAttr => {
@@ -748,8 +808,8 @@ impl CompInfo {
CXChildVisit_Continue
});
- if let Some((ty, _)) = maybe_anonymous_struct_field {
- let field = Field::new(None, ty, None, None, None, false);
+ if let Some((ty, _, offset)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false, offset);
ci.fields.push(field);
}
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index 8ea7a8dc..0a85577e 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -5,6 +5,8 @@ use super::item::Item;
use super::ty::TypeKind;
use clang;
use ir::annotations::Annotations;
+use ir::int::IntKind;
+use ir::layout::Layout;
use parse::{ClangItemParser, ParseError};
/// An enum representing custom handling that can be given to a variant.
@@ -49,6 +51,19 @@ impl Enum {
&self.variants
}
+ /// Compute the layout of this type.
+ pub fn calc_layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ self.repr
+ .map(|repr| ctx.resolve_type(repr))
+ .and_then(|repr| match *repr.canonical_type(ctx).kind() {
+ TypeKind::Int(int_kind) => Some(int_kind),
+ _ => None,
+ })
+ .unwrap_or(IntKind::Int)
+ .known_size()
+ .map(|size| Layout::new(size, size))
+ }
+
/// Construct an enumeration from the given Clang type.
pub fn from_ty(ty: &clang::Type,
ctx: &mut BindgenContext)
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index f0a8c545..5903430c 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -12,6 +12,7 @@ use super::objc::ObjCInterface;
use super::type_collector::{ItemSet, TypeCollector};
use clang::{self, Cursor};
use parse::{ClangItemParser, ParseError, ParseResult};
+use std::mem;
/// The base representation of a type in bindgen.
///
@@ -356,6 +357,40 @@ impl Type {
_ => false,
}
}
+
+ /// If this type has a known size, return it (in bytes).
+ pub fn calc_size(&self, ctx: &BindgenContext) -> Option<usize> {
+ match self.kind {
+ TypeKind::Comp(ref ci) => {
+ ci.calc_layout(ctx).map(|layout| layout.size)
+ }
+ TypeKind::Enum(ref enum_ty) => {
+ enum_ty.calc_layout(ctx).map(|layout| layout.size)
+ }
+ TypeKind::Int(int_kind) => int_kind.known_size(),
+ TypeKind::Float(float_kind) => Some(float_kind.known_size()),
+ TypeKind::Complex(float_kind) => Some(float_kind.known_size() * 2),
+ TypeKind::Reference(..) |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) |
+ TypeKind::BlockPointer |
+ TypeKind::Function(..) |
+ TypeKind::ObjCInterface(..) => Some(mem::size_of::<*mut ()>()),
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(inner) |
+ TypeKind::TemplateAlias(inner, _) |
+ TypeKind::TemplateRef(inner, _) => {
+ ctx.resolve_type(inner).calc_size(ctx)
+ }
+ TypeKind::Array(inner, len) => {
+ ctx.resolve_type(inner)
+ .layout(ctx)
+ .map(|layout| layout.size * len)
+ }
+ TypeKind::Void | TypeKind::Named => None,
+ TypeKind::UnresolvedTypeRef(..) => unreachable!(),
+ }
+ }
}
impl CanDeriveDebug for Type {
@@ -425,6 +460,17 @@ pub enum FloatKind {
Float128,
}
+impl FloatKind {
+ /// If this type has a known size, return it (in bytes).
+ pub fn known_size(&self) -> usize {
+ match *self {
+ FloatKind::Float => mem::size_of::<f32>(),
+ FloatKind::Double | FloatKind::LongDouble => mem::size_of::<f64>(),
+ FloatKind::Float128 => mem::size_of::<f64>() * 2,
+ }
+ }
+}
+
/// The different kinds of types that we can parse.
#[derive(Debug)]
pub enum TypeKind {
@@ -623,7 +669,9 @@ impl Type {
// assume this is a Comp(..)
} else if ty.is_fully_specialized_template() {
debug!("Template specialization: {:?}, {:?} {:?}",
- ty, location, canonical_ty);
+ ty,
+ location,
+ canonical_ty);
let complex =
CompInfo::from_ty(potential_id, ty, location, ctx)
.expect("C'mon");