summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clang.rs5
-rw-r--r--src/codegen/mod.rs18
-rw-r--r--src/ir/comp.rs18
-rw-r--r--tests/expectations/tests/forward_declared_complex_types.rs50
-rw-r--r--tests/expectations/tests/same_struct_name_in_different_namespaces.rs8
-rw-r--r--tests/headers/forward_declared_complex_types.hpp16
6 files changed, 106 insertions, 9 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 491aaa07..9cf51436 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -190,6 +190,11 @@ impl Cursor {
unsafe { clang_getCursorKind(self.x) }
}
+ /// Returns true is the cursor is a definition
+ pub fn is_definition(&self) -> bool {
+ unsafe { clang_isCursorDefinition(self.x) != 0 }
+ }
+
/// Is the referent an anonymous record definition?
pub fn is_anonymous(&self) -> bool {
unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 0991391a..c92e95fa 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -763,6 +763,22 @@ impl CodeGenerator for CompInfo {
return;
}
+ let applicable_template_args = item.applicable_template_args(ctx);
+
+ // generate tuple struct if struct or union is a forward declaration,
+ // skip for now if template parameters are needed.
+ if self.is_forward_declaration() && applicable_template_args.is_empty(){
+ let struct_name = item.canonical_name(ctx);
+ let struct_name = ctx.rust_ident_raw(&struct_name);
+ let tuple_struct = quote_item!(ctx.ext_cx(),
+ #[repr(C)]
+ pub struct $struct_name([u8; 0]);
+ )
+ .unwrap();
+ result.push(tuple_struct);
+ return;
+ }
+
if self.is_template_specialization() {
let layout = item.kind().expect_type().layout(ctx);
@@ -790,8 +806,6 @@ impl CodeGenerator for CompInfo {
return;
}
- let applicable_template_args = item.applicable_template_args(ctx);
-
let mut attributes = vec![];
let mut needs_clone_impl = false;
if let Some(comment) = item.comment() {
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index ac68b672..4eea1d7a 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -290,6 +290,10 @@ pub struct CompInfo {
/// Used to detect if we've run in a has_destructor cycle while cycling
/// around the template arguments.
detect_has_destructor_cycle: Cell<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 {
@@ -314,6 +318,7 @@ impl CompInfo {
found_unknown_attr: false,
detect_derive_debug_cycle: Cell::new(false),
detect_has_destructor_cycle: Cell::new(false),
+ is_forward_declaration: false,
}
}
@@ -481,6 +486,14 @@ impl CompInfo {
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_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassDecl => !cur.is_definition(),
+ _ => false,
+ }
+ });
ci.is_anonymous = cursor.is_anonymous();
ci.template_args = match ty.template_args() {
// In forward declarations and not specializations,
@@ -822,6 +835,11 @@ impl CompInfo {
.map_or(false, |ci| ci.has_vtable(ctx))
})
}
+
+ /// Returns true if compound type has been forward declared
+ pub fn is_forward_declaration(&self) -> bool {
+ self.is_forward_declaration
+ }
}
impl CanDeriveDebug for CompInfo {
diff --git a/tests/expectations/tests/forward_declared_complex_types.rs b/tests/expectations/tests/forward_declared_complex_types.rs
new file mode 100644
index 00000000..77849a91
--- /dev/null
+++ b/tests/expectations/tests/forward_declared_complex_types.rs
@@ -0,0 +1,50 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Foo_empty {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Foo_empty() {
+ assert_eq!(::std::mem::size_of::<Foo_empty>() , 1usize);
+ assert_eq!(::std::mem::align_of::<Foo_empty>() , 1usize);
+}
+impl Clone for Foo_empty {
+ fn clone(&self) -> Self { *self }
+}
+#[repr(C)]
+pub struct Foo([u8; 0]);
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Bar {
+ pub f: *mut Foo,
+}
+#[test]
+fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 8usize);
+ assert_eq!(::std::mem::align_of::<Bar>() , 8usize);
+}
+impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+}
+extern "C" {
+ #[link_name = "_Z10baz_structP3Foo"]
+ pub fn baz_struct(f: *mut Foo);
+}
+#[repr(C)]
+pub struct Union([u8; 0]);
+extern "C" {
+ #[link_name = "_Z9baz_unionP5Union"]
+ pub fn baz_union(u: *mut Union);
+}
+#[repr(C)]
+pub struct Quux([u8; 0]);
+extern "C" {
+ #[link_name = "_Z9baz_classP4Quux"]
+ pub fn baz_class(q: *mut Quux);
+}
diff --git a/tests/expectations/tests/same_struct_name_in_different_namespaces.rs b/tests/expectations/tests/same_struct_name_in_different_namespaces.rs
index 8e7c177b..c59e4d44 100644
--- a/tests/expectations/tests/same_struct_name_in_different_namespaces.rs
+++ b/tests/expectations/tests/same_struct_name_in_different_namespaces.rs
@@ -5,13 +5,7 @@
#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct JS_Zone {
- pub _address: u8,
-}
-impl Clone for JS_Zone {
- fn clone(&self) -> Self { *self }
-}
+pub struct JS_Zone([u8; 0]);
#[repr(C)]
#[derive(Debug, Copy)]
pub struct JS_shadow_Zone {
diff --git a/tests/headers/forward_declared_complex_types.hpp b/tests/headers/forward_declared_complex_types.hpp
new file mode 100644
index 00000000..ffc779ad
--- /dev/null
+++ b/tests/headers/forward_declared_complex_types.hpp
@@ -0,0 +1,16 @@
+struct Foo_empty {};
+struct Foo;
+
+struct Bar {
+ Foo *f;
+};
+
+void baz_struct(Foo* f);
+
+union Union;
+
+void baz_union(Union* u);
+
+class Quux;
+
+void baz_class(Quux* q);