Skip to content
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

Forward declared structs now generate opaque enums #370

Merged
merged 2 commits into from
Jan 26, 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
5 changes: 5 additions & 0 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
18 changes: 16 additions & 2 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,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);

Expand Down Expand Up @@ -775,8 +791,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() {
Expand Down
18 changes: 18 additions & 0 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
50 changes: 50 additions & 0 deletions tests/expectations/tests/forward_declared_complex_types.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 16 additions & 0 deletions tests/headers/forward_declared_complex_types.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
struct Foo_empty {};
struct Foo;

struct Bar {
Foo *f;
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add an empty struct (struct Baz {}), and verify that it doesn't produce an opaque enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added :)

void baz_struct(Foo* f);

union Union;

void baz_union(Union* u);

class Quux;

void baz_class(Quux* q);