Skip to content

Tidy up and test virtual inheritance handling. #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions libbindgen/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod helpers;
use aster;

use ir::annotations::FieldAccessorKind;
use ir::comp::{CompInfo, CompKind, Field, Method, MethodKind};
use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind};
use ir::context::{BindgenContext, ItemId};
use ir::derive::{CanDeriveCopy, CanDeriveDebug};
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
Expand Down Expand Up @@ -556,13 +556,13 @@ struct Vtable<'a> {
#[allow(dead_code)]
methods: &'a [Method],
#[allow(dead_code)]
base_classes: &'a [ItemId],
base_classes: &'a [Base],
}

impl<'a> Vtable<'a> {
fn new(item_id: ItemId,
methods: &'a [Method],
base_classes: &'a [ItemId])
base_classes: &'a [Base])
-> Self {
Vtable {
item_id: item_id,
Expand Down Expand Up @@ -835,14 +835,18 @@ impl CodeGenerator for CompInfo {
}

for (i, base) in self.base_members().iter().enumerate() {
let base_ty = ctx.resolve_type(*base);
// Virtual bases are already taken into account by the vtable
// pointer.
//
// FIXME(emilio): Is this always right?
if base.is_virtual() {
continue;
}

let base_ty = ctx.resolve_type(base.ty);
// NB: We won't include unsized types in our base chain because they
// would contribute to our size given the dummy field we insert for
// unsized types.
//
// NB: Canonical type is here because it could be inheriting from a
// typedef, for example, and the lack of `unwrap()` is because we
// can inherit from a template parameter, yes.
if base_ty.is_unsized(ctx) {
continue;
}
Expand All @@ -854,7 +858,7 @@ impl CodeGenerator for CompInfo {
}
}

let inner = base.to_rust_ty(ctx);
let inner = base.ty.to_rust_ty(ctx);
let field_name = if i == 0 {
"_base".into()
} else {
Expand Down
81 changes: 62 additions & 19 deletions libbindgen/src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,40 @@ impl<'a> CanDeriveCopy<'a> for Field {
}
}


/// 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: ItemId,
/// The kind of inheritance we're doing.
pub kind: BaseKind,
}

impl Base {
/// Whether this base class is inheriting virtually.
pub fn is_virtual(&self) -> bool {
self.kind == BaseKind::Virtual
}
}

/// A compound type.
///
/// Either a struct or union, a compound type is built up from the combination
Expand All @@ -199,7 +233,7 @@ pub struct CompInfo {
constructors: Vec<ItemId>,

/// Vector of classes this one inherits from.
base_members: Vec<ItemId>,
base_members: Vec<Base>,

/// The parent reference template if any.
ref_template: Option<ItemId>,
Expand Down Expand Up @@ -287,7 +321,7 @@ impl CompInfo {
pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
!self.has_vtable(ctx) && self.fields.is_empty() &&
self.base_members.iter().all(|base| {
ctx.resolve_type(*base).canonical_type(ctx).is_unsized(ctx)
ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
}) &&
self.ref_template
.map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
Expand All @@ -314,12 +348,12 @@ impl CompInfo {
self.ref_template.as_ref().map_or(false, |t| {
ctx.resolve_type(*t).has_destructor(ctx)
}) ||
self.template_args
.iter()
.any(|t| ctx.resolve_type(*t).has_destructor(ctx)) ||
self.base_members
.iter()
.any(|t| ctx.resolve_type(*t).has_destructor(ctx)) ||
self.template_args.iter().any(|t| {
ctx.resolve_type(*t).has_destructor(ctx)
}) ||
self.base_members.iter().any(|base| {
ctx.resolve_type(base.ty).has_destructor(ctx)
}) ||
self.fields.iter().any(|field| {
ctx.resolve_type(field.ty)
.has_destructor(ctx)
Expand Down Expand Up @@ -394,7 +428,7 @@ impl CompInfo {
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
self.has_vtable ||
self.base_members().iter().any(|base| {
ctx.resolve_type(*base)
ctx.resolve_type(base.ty)
.has_vtable(ctx)
}) ||
self.ref_template.map_or(false, |template| {
Expand All @@ -418,7 +452,7 @@ impl CompInfo {
}

/// The set of types that this one inherits from.
pub fn base_members(&self) -> &[ItemId] {
pub fn base_members(&self) -> &[Base] {
&self.base_members
}

Expand Down Expand Up @@ -590,14 +624,23 @@ impl CompInfo {
ci.template_args.push(param);
}
CXCursor_CXXBaseSpecifier => {
if !ci.has_vtable {
ci.has_vtable = cur.is_virtual_base();
}
let is_virtual_base = cur.is_virtual_base();
ci.has_vtable |= is_virtual_base;

let kind = if is_virtual_base {
BaseKind::Virtual
} else {
BaseKind::Normal
};

let type_id = Item::from_ty_or_ref(cur.cur_type(),
Some(cur),
None,
ctx);
ci.base_members.push(type_id);
ci.base_members.push(Base {
ty: type_id,
kind: kind,
});
}
CXCursor_Constructor |
CXCursor_Destructor |
Expand Down Expand Up @@ -794,7 +837,7 @@ impl CompInfo {
// Unfortunately, given the way we implement --match-pat, and also
// that you can inherit from templated types, we need to handle
// other cases here too.
ctx.resolve_type(*base)
ctx.resolve_type(base.ty)
.canonical_type(ctx)
.as_comp()
.map_or(false, |ci| ci.has_vtable(ctx))
Expand Down Expand Up @@ -835,7 +878,7 @@ impl CanDeriveDebug for CompInfo {
let can_derive_debug = {
self.base_members
.iter()
.all(|id| id.can_derive_debug(ctx, ())) &&
.all(|base| base.ty.can_derive_debug(ctx, ())) &&
self.template_args
.iter()
.all(|id| id.can_derive_debug(ctx, ())) &&
Expand Down Expand Up @@ -888,7 +931,7 @@ impl<'a> CanDeriveCopy<'a> for CompInfo {
.map_or(true, |t| t.can_derive_copy(ctx, ())) &&
self.base_members
.iter()
.all(|t| t.can_derive_copy(ctx, ())) &&
.all(|base| base.ty.can_derive_copy(ctx, ())) &&
self.fields.iter().all(|field| field.can_derive_copy(ctx, ()))
}

Expand Down Expand Up @@ -916,8 +959,8 @@ impl TypeCollector for CompInfo {
types.insert(arg);
}

for &base in self.base_members() {
types.insert(base);
for base in self.base_members() {
types.insert(base.ty);
}

for field in self.fields() {
Expand Down
68 changes: 68 additions & 0 deletions libbindgen/tests/expectations/tests/virtual_inheritance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


#[repr(C)]
#[derive(Debug, Copy)]
pub struct A {
pub foo: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_A() {
assert_eq!(::std::mem::size_of::<A>() , 4usize);
assert_eq!(::std::mem::align_of::<A>() , 4usize);
}
impl Clone for A {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
pub struct B__bindgen_vtable {
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct B {
pub vtable_: *const B__bindgen_vtable,
pub bar: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_B() {
assert_eq!(::std::mem::size_of::<B>() , 16usize);
assert_eq!(::std::mem::align_of::<B>() , 8usize);
}
impl Clone for B {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
pub struct C__bindgen_vtable {
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct C {
pub vtable_: *const C__bindgen_vtable,
pub baz: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_C() {
assert_eq!(::std::mem::size_of::<C>() , 16usize);
assert_eq!(::std::mem::align_of::<C>() , 8usize);
}
impl Clone for C {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct D {
pub _base: C,
pub _base_1: B,
pub bazz: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_D() {
assert_eq!(::std::mem::size_of::<D>() , 40usize);
assert_eq!(::std::mem::align_of::<D>() , 8usize);
}
impl Clone for D {
fn clone(&self) -> Self { *self }
}
16 changes: 16 additions & 0 deletions libbindgen/tests/headers/virtual_inheritance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

class A {
int foo;
};

class B: public virtual A {
int bar;
};

class C: public virtual A {
int baz;
};

class D: public C, public B {
int bazz;
};