summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parser.rs4
-rw-r--r--src/types.rs38
-rw-r--r--tests/expectations/vtable_recursive_sig.rs36
-rw-r--r--tests/headers/vtable_recursive_sig.hpp11
4 files changed, 86 insertions, 3 deletions
diff --git a/src/parser.rs b/src/parser.rs
index a3311b24..bb1e535d 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -987,8 +987,8 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
}
}
for base in ci.members[..ci.base_members].iter() {
- let base = match base {
- &CompMember::Field(ref fi) => {
+ let base = match *base {
+ CompMember::Field(ref fi) => {
match fi.ty {
TComp(ref ci) => ci.clone(),
_ => continue,
diff --git a/src/types.rs b/src/types.rs
index 9f640620..30a4f454 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -167,7 +167,8 @@ pub struct FuncSig {
pub abi: abi::Abi,
}
-#[derive(Clone, PartialEq, Debug)]
+// NOTE: Remember to add your new variant to the PartialEq implementation below!
+#[derive(Clone, Debug)]
pub enum Type {
TVoid,
TInt(IKind, Layout),
@@ -181,6 +182,41 @@ pub enum Type {
TEnum(Rc<RefCell<EnumInfo>>)
}
+/// Compares to Rc<T> types looking first at the value they point to.
+///
+/// This is needed to avoid infinite recursion in things like virtual function
+/// signatures.
+fn ref_ptr_aware_eq<T: PartialEq>(one: &Rc<T>, other: &Rc<T>) -> bool {
+ &**one as *const T == &**other as *const T ||
+ **one == **other
+}
+
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (&TVoid, &TVoid)
+ => true,
+ (&TInt(ref kind, ref l), &TInt(ref o_kind, ref o_l))
+ => kind == o_kind && l == o_l,
+ (&TFloat(ref kind, ref l), &TFloat(ref o_kind, ref o_l))
+ => kind == o_kind && l == o_l,
+ (&TPtr(ref ty, is_const, is_ref, ref l), &TPtr(ref o_ty, o_is_const, o_is_ref, ref o_l))
+ => is_const == o_is_const && is_ref == o_is_ref && l == o_l && ty == o_ty,
+ (&TArray(ref ty, count, ref l), &TArray(ref o_ty, o_count, ref o_l))
+ => count == o_count && l == o_l && ty == o_ty,
+ (&TFuncProto(ref sig), &TFuncProto(ref o_sig))
+ => sig == o_sig,
+ (&TNamed(ref ti), &TNamed(ref o_ti))
+ => ref_ptr_aware_eq(ti, o_ti),
+ (&TComp(ref ci), &TComp(ref o_ci))
+ => ref_ptr_aware_eq(ci, o_ci),
+ (&TEnum(ref ei), &TEnum(ref o_ei))
+ => ref_ptr_aware_eq(ei, o_ei),
+ _ => false,
+ }
+ }
+}
+
impl Type {
#[allow(dead_code)]
pub fn name(&self) -> Option<String> {
diff --git a/tests/expectations/vtable_recursive_sig.rs b/tests/expectations/vtable_recursive_sig.rs
new file mode 100644
index 00000000..8f972e92
--- /dev/null
+++ b/tests/expectations/vtable_recursive_sig.rs
@@ -0,0 +1,36 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Base {
+ pub _vftable: *const _vftable_Base,
+}
+#[repr(C)]
+pub struct _vftable_Base {
+ pub AsDerived: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void)
+ -> *mut Derived,
+}
+impl ::std::clone::Clone for Base {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Base() {
+ assert_eq!(::std::mem::size_of::<Base>() , 8usize);
+ assert_eq!(::std::mem::align_of::<Base>() , 8usize);
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Derived {
+ pub _base: Base,
+}
+#[repr(C)]
+pub struct _vftable_Derived {
+ pub _base: _vftable_Base,
+}
+impl ::std::clone::Clone for Derived {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/headers/vtable_recursive_sig.hpp b/tests/headers/vtable_recursive_sig.hpp
new file mode 100644
index 00000000..4e5af806
--- /dev/null
+++ b/tests/headers/vtable_recursive_sig.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -std=c++11 -no-type-renaming
+
+class Derived;
+class Base {
+public:
+ virtual Derived* AsDerived() { return nullptr; }
+};
+
+class Derived final : public Base {
+ virtual Derived* AsDerived() override { return this; }
+};