Skip to content

Commit 53c18d3

Browse files
committed
Make opaque items with themplate parameters generate a struct.
They're instantiable, yes, but otherwise there's no way they'd work correctly.
1 parent a2eefa3 commit 53c18d3

File tree

5 files changed

+109
-67
lines changed

5 files changed

+109
-67
lines changed

src/gen.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,11 @@ fn gen_global(mut ctx: &mut GenCtx,
386386
GCompDecl(ci) => {
387387
let c = ci.borrow().clone();
388388
let name = comp_name(&ctx, c.kind, &c.name);
389-
390-
defs.push(opaque_to_rs(&mut ctx, &name, c.layout));
389+
if !c.args.is_empty() {
390+
defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter());
391+
} else {
392+
defs.push(opaque_to_rs(&mut ctx, &name, c.layout));
393+
}
391394
},
392395
GComp(ci) => {
393396
let c = ci.borrow().clone();
@@ -1145,21 +1148,8 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
11451148
} else {
11461149
ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID)
11471150
};
1148-
let ty_params = template_args.iter().map(|gt| {
1149-
let name = match gt {
1150-
&TNamed(ref ti) => {
1151-
ctx.ext_cx.ident_of(&ti.borrow().name)
1152-
},
1153-
_ => ctx.ext_cx.ident_of("")
1154-
};
1155-
ast::TyParam {
1156-
ident: name,
1157-
id: ast::DUMMY_NODE_ID,
1158-
bounds: P::new(),
1159-
default: None,
1160-
span: ctx.span
1161-
}
1162-
}).collect();
1151+
1152+
let ty_params = mk_ty_params(ctx, &template_args);
11631153

11641154
let def = ast::ItemKind::Struct(
11651155
variant_data,
@@ -2277,6 +2267,25 @@ fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec<P<ast::Ite
22772267
ret
22782268
}
22792269

2270+
/// Generates a vector of rust's ty params from a list of types
2271+
fn mk_ty_params(ctx: &GenCtx, template_args: &[Type]) -> Vec<ast::TyParam> {
2272+
template_args.iter().map(|gt| {
2273+
let name = match *gt {
2274+
TNamed(ref ti) => {
2275+
ctx.ext_cx.ident_of(&ti.borrow().name)
2276+
},
2277+
_ => ctx.ext_cx.ident_of("")
2278+
};
2279+
ast::TyParam {
2280+
ident: name,
2281+
id: ast::DUMMY_NODE_ID,
2282+
bounds: P::new(),
2283+
default: None,
2284+
span: ctx.span
2285+
}
2286+
}).collect()
2287+
}
2288+
22802289
fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut ast::Item) {
22812290
if !ctx.saw_union {
22822291
return;

src/parser.rs

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
7171
ctx.options.match_pat.iter().any(|pat| name.contains(pat))
7272
}
7373

74+
fn conv_template_type_parameter(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Type {
75+
assert_eq!(cursor.kind(), CXCursor_TemplateTypeParameter);
76+
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
77+
let layout = Layout::new(ty.size(), ty.align());
78+
TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout))))
79+
}
80+
7481
fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
7582
let cursor = cursor.canonical();
7683
let override_enum_ty = ctx.options.override_enum_ty;
@@ -101,26 +108,31 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
101108
let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling);
102109

103110
let mut has_non_type_template_params = false;
104-
let args = match cursor.kind() {
105-
CXCursor_ClassDecl => {
106-
match ty.num_template_args() {
107-
-1 => vec![],
108-
len => {
109-
let mut list = Vec::with_capacity(len as usize);
110-
for i in 0..len {
111-
let arg_type = ty.template_arg_type(i);
112-
if arg_type.kind() != CXType_Invalid {
113-
list.push(conv_ty(ctx, &arg_type, &cursor));
114-
} else {
115-
has_non_type_template_params = true;
116-
ctx.logger.warn("warning: Template parameter is not a type");
117-
}
118-
}
119-
list
111+
let args = match ty.num_template_args() {
112+
// In forward declarations, etc, they are in the ast... sigh
113+
-1 => {
114+
let mut args = vec![];
115+
cursor.visit(|c, _| {
116+
if c.kind() == CXCursor_TemplateTypeParameter {
117+
args.push(conv_template_type_parameter(ctx, c));
118+
}
119+
CXChildVisit_Continue
120+
});
121+
args
122+
}
123+
len => {
124+
let mut list = Vec::with_capacity(len as usize);
125+
for i in 0..len {
126+
let arg_type = ty.template_arg_type(i);
127+
if arg_type.kind() != CXType_Invalid {
128+
list.push(conv_ty(ctx, &arg_type, &cursor));
129+
} else {
130+
has_non_type_template_params = true;
131+
ctx.logger.warn("warning: Template parameter is not a type");
120132
}
121133
}
134+
list
122135
}
123-
_ => vec![],
124136
};
125137

126138
let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout);
@@ -210,6 +222,7 @@ fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) {
210222
}
211223

212224
let name = decl_name(ctx, decl);
225+
println!("{:?}", name);
213226
ctx.current_module_mut().globals.push(name);
214227
}
215228

@@ -602,41 +615,41 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
602615
// incomplete type via the declaration or anything like
603616
// that. We can inspect the AST and deduct them though,
604617
// since there's a leading CXCursor_TemplateRef.
605-
if child_ci.args.is_empty() {
618+
if child_ci.args.is_empty() && child_cursor.kind() == CXCursor_ClassDecl {
606619
// println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(),
607620
// type_to_str(cursor_ty.kind()),
608621
// type_to_str(child_cursor.cur_type().kind()),
609622
// kind_to_str(child_cursor.kind()));
610-
match child_cursor.kind() {
611-
CXCursor_ClassDecl => {
612-
if child_ci.name == ci.name &&
613-
child_ci.module_id == ci.module_id {
614-
child_ci.args = ci.args.clone();
615-
}
623+
if child_ci.name == ci.name &&
624+
child_ci.module_id == ci.module_id {
625+
child_ci.args = ci.args.clone();
626+
}
627+
}
628+
629+
if child_cursor.kind() == CXCursor_ClassTemplate {
630+
// We need to take into account the possibly different
631+
// type template names, so we need to clear them and
632+
// re-scan.
633+
child_ci.args.clear();
634+
let mut found_invalid_template_ref = false;
635+
cursor.visit(|c, _| {
636+
// println!("ichild: {:?} {:?}, {:?}", c.spelling(),
637+
// kind_to_str(c.kind()),
638+
// type_to_str(c.cur_type().kind()));
639+
if c.kind() == CXCursor_TemplateRef &&
640+
c.cur_type().kind() == CXType_Invalid {
641+
found_invalid_template_ref = true;
616642
}
617-
CXCursor_ClassTemplate => {
618-
let mut found_invalid_template_ref = false;
619-
cursor.visit(|c, _| {
620-
// println!("ichild: {:?} {:?}, {:?}", c.spelling(),
621-
// kind_to_str(c.kind()),
622-
// type_to_str(c.cur_type().kind()));
623-
if c.kind() == CXCursor_TemplateRef &&
624-
c.cur_type().kind() == CXType_Invalid {
625-
found_invalid_template_ref = true;
626-
}
627-
if found_invalid_template_ref &&
628-
c.kind() == CXCursor_TypeRef {
629-
child_ci.args.push(TNamed(Rc::new(RefCell::new(
630-
TypeInfo::new(c.spelling(),
631-
ctx.current_module_id,
632-
TVoid,
633-
Layout::zero())))));
634-
}
635-
CXChildVisit_Continue
636-
})
643+
if found_invalid_template_ref &&
644+
c.kind() == CXCursor_TypeRef {
645+
child_ci.args.push(TNamed(Rc::new(RefCell::new(
646+
TypeInfo::new(c.spelling(),
647+
ctx.current_module_id,
648+
TVoid,
649+
Layout::zero())))));
637650
}
638-
_ => {}
639-
}
651+
CXChildVisit_Continue
652+
})
640653
}
641654
}
642655
}
@@ -796,9 +809,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
796809
ci.layout.packed = true;
797810
}
798811
CXCursor_TemplateTypeParameter => {
799-
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
800-
let layout = Layout::new(ty.size(), ty.align());
801-
ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))));
812+
ci.args.push(conv_template_type_parameter(ctx, cursor));
802813
}
803814
CXCursor_EnumDecl => {
804815
let anno = Annotations::new(cursor);

tests/expectations/namespace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod root {
1414
pub m_c: T,
1515
pub m_c_ptr: *mut T,
1616
pub m_c_arr: [T; 10usize],
17+
pub _phantom0: ::std::marker::PhantomData<T>,
1718
}
1819
extern "C" {
1920
#[link_name = "_Z9top_levelv"]
@@ -57,7 +58,6 @@ pub mod root {
5758
#[derive(Debug)]
5859
pub struct Struct_D<T> {
5960
pub m_c: root::Struct_C<T>,
60-
pub _phantom0: ::std::marker::PhantomData<T>,
6161
}
6262
extern "C" {
6363
#[link_name = "_ZN1w3hehEv"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![feature(const_fn)]
5+
#![allow(non_snake_case)]
6+
7+
8+
#[repr(C)]
9+
#[derive(Debug, Copy, Clone)]
10+
pub struct Struct_RandomTemplate<T> {
11+
pub _phantom0: ::std::marker::PhantomData<T>,
12+
}
13+
#[repr(C)]
14+
pub struct ShouldBeOpaque;
15+
pub type ShouldNotBeOpaque = Struct_RandomTemplate<::std::os::raw::c_int>;

tests/headers/opaque_typedef.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
template<typename T>
2+
class RandomTemplate;
3+
4+
/** <div rustbindgen opaque></div> */
5+
typedef RandomTemplate<int> ShouldBeOpaque;
6+
7+
typedef RandomTemplate<int> ShouldNotBeOpaque;

0 commit comments

Comments
 (0)