Skip to content

Commit 5cc2506

Browse files
author
bors-servo
authored
Auto merge of rust-lang#370 - cynicaldevil:detect-forward, r=emilio
Forward declared structs now generate opaque enums @emilio : I checked the test outputs again, and it seems that these changes are affecting struct *definitions* as well. Hence, I have not committed the test changes yet. Fixes rust-lang#62
2 parents e4420b6 + 78aaa32 commit 5cc2506

File tree

6 files changed

+106
-9
lines changed

6 files changed

+106
-9
lines changed

src/clang.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ impl Cursor {
190190
unsafe { clang_getCursorKind(self.x) }
191191
}
192192

193+
/// Returns true is the cursor is a definition
194+
pub fn is_definition(&self) -> bool {
195+
unsafe { clang_isCursorDefinition(self.x) != 0 }
196+
}
197+
193198
/// Is the referent an anonymous record definition?
194199
pub fn is_anonymous(&self) -> bool {
195200
unsafe { clang_Cursor_isAnonymous(self.x) != 0 }

src/codegen/mod.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,22 @@ impl CodeGenerator for CompInfo {
763763
return;
764764
}
765765

766+
let applicable_template_args = item.applicable_template_args(ctx);
767+
768+
// generate tuple struct if struct or union is a forward declaration,
769+
// skip for now if template parameters are needed.
770+
if self.is_forward_declaration() && applicable_template_args.is_empty(){
771+
let struct_name = item.canonical_name(ctx);
772+
let struct_name = ctx.rust_ident_raw(&struct_name);
773+
let tuple_struct = quote_item!(ctx.ext_cx(),
774+
#[repr(C)]
775+
pub struct $struct_name([u8; 0]);
776+
)
777+
.unwrap();
778+
result.push(tuple_struct);
779+
return;
780+
}
781+
766782
if self.is_template_specialization() {
767783
let layout = item.kind().expect_type().layout(ctx);
768784

@@ -790,8 +806,6 @@ impl CodeGenerator for CompInfo {
790806
return;
791807
}
792808

793-
let applicable_template_args = item.applicable_template_args(ctx);
794-
795809
let mut attributes = vec![];
796810
let mut needs_clone_impl = false;
797811
if let Some(comment) = item.comment() {

src/ir/comp.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ pub struct CompInfo {
290290
/// Used to detect if we've run in a has_destructor cycle while cycling
291291
/// around the template arguments.
292292
detect_has_destructor_cycle: Cell<bool>,
293+
294+
/// Used to indicate when a struct has been forward declared. Usually used
295+
/// in headers so that APIs can't modify them directly.
296+
is_forward_declaration: bool,
293297
}
294298

295299
impl CompInfo {
@@ -314,6 +318,7 @@ impl CompInfo {
314318
found_unknown_attr: false,
315319
detect_derive_debug_cycle: Cell::new(false),
316320
detect_has_destructor_cycle: Cell::new(false),
321+
is_forward_declaration: false,
317322
}
318323
}
319324

@@ -481,6 +486,14 @@ impl CompInfo {
481486
debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
482487

483488
let mut ci = CompInfo::new(kind);
489+
ci.is_forward_declaration = location.map_or(true, |cur| {
490+
match cur.kind() {
491+
CXCursor_StructDecl |
492+
CXCursor_UnionDecl |
493+
CXCursor_ClassDecl => !cur.is_definition(),
494+
_ => false,
495+
}
496+
});
484497
ci.is_anonymous = cursor.is_anonymous();
485498
ci.template_args = match ty.template_args() {
486499
// In forward declarations and not specializations,
@@ -822,6 +835,11 @@ impl CompInfo {
822835
.map_or(false, |ci| ci.has_vtable(ctx))
823836
})
824837
}
838+
839+
/// Returns true if compound type has been forward declared
840+
pub fn is_forward_declaration(&self) -> bool {
841+
self.is_forward_declaration
842+
}
825843
}
826844

827845
impl CanDeriveDebug for CompInfo {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy)]
9+
pub struct Foo_empty {
10+
pub _address: u8,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Foo_empty() {
14+
assert_eq!(::std::mem::size_of::<Foo_empty>() , 1usize);
15+
assert_eq!(::std::mem::align_of::<Foo_empty>() , 1usize);
16+
}
17+
impl Clone for Foo_empty {
18+
fn clone(&self) -> Self { *self }
19+
}
20+
#[repr(C)]
21+
pub struct Foo([u8; 0]);
22+
#[repr(C)]
23+
#[derive(Debug, Copy)]
24+
pub struct Bar {
25+
pub f: *mut Foo,
26+
}
27+
#[test]
28+
fn bindgen_test_layout_Bar() {
29+
assert_eq!(::std::mem::size_of::<Bar>() , 8usize);
30+
assert_eq!(::std::mem::align_of::<Bar>() , 8usize);
31+
}
32+
impl Clone for Bar {
33+
fn clone(&self) -> Self { *self }
34+
}
35+
extern "C" {
36+
#[link_name = "_Z10baz_structP3Foo"]
37+
pub fn baz_struct(f: *mut Foo);
38+
}
39+
#[repr(C)]
40+
pub struct Union([u8; 0]);
41+
extern "C" {
42+
#[link_name = "_Z9baz_unionP5Union"]
43+
pub fn baz_union(u: *mut Union);
44+
}
45+
#[repr(C)]
46+
pub struct Quux([u8; 0]);
47+
extern "C" {
48+
#[link_name = "_Z9baz_classP4Quux"]
49+
pub fn baz_class(q: *mut Quux);
50+
}

tests/expectations/tests/same_struct_name_in_different_namespaces.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55

66

77
#[repr(C)]
8-
#[derive(Debug, Copy)]
9-
pub struct JS_Zone {
10-
pub _address: u8,
11-
}
12-
impl Clone for JS_Zone {
13-
fn clone(&self) -> Self { *self }
14-
}
8+
pub struct JS_Zone([u8; 0]);
159
#[repr(C)]
1610
#[derive(Debug, Copy)]
1711
pub struct JS_shadow_Zone {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
struct Foo_empty {};
2+
struct Foo;
3+
4+
struct Bar {
5+
Foo *f;
6+
};
7+
8+
void baz_struct(Foo* f);
9+
10+
union Union;
11+
12+
void baz_union(Union* u);
13+
14+
class Quux;
15+
16+
void baz_class(Quux* q);

0 commit comments

Comments
 (0)