Skip to content

Commit 774c7da

Browse files
committed
Refactor how template specialisations are tracked to prevent borrow panics
1 parent ca9f853 commit 774c7da

File tree

7 files changed

+84
-66
lines changed

7 files changed

+84
-66
lines changed

src/gen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2014,7 +2014,7 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool)
20142014
}).collect();
20152015

20162016
if use_full_path {
2017-
let mut path = ctx.full_path_for_module(c.module_id);
2017+
let mut path = ctx.full_path_for_module(c.module_id());
20182018
path.push(id);
20192019
mk_ty_args(ctx, false, &path, args)
20202020
} else {

src/parser.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
9797
CompKind::Struct
9898
};
9999

100-
let mut opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling);
100+
let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling);
101101
let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling);
102102

103103
let mut has_non_type_template_params = false;
@@ -123,30 +123,19 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
123123
_ => vec![],
124124
};
125125

126-
let mut module_id = ctx.current_module_id;
127-
let mut has_dtor = false;
126+
let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout);
128127

129128
// If it's an instantiation of another template,
130129
// find the canonical declaration to find the module
131130
// it belongs to and if it's opaque.
132131
let parent = cursor.specialized();
133132
if let Some(parent) = ctx.name.get(&parent) {
134-
match *parent {
135-
GComp(ref ci) |
136-
GCompDecl(ref ci) => {
137-
opaque |= ci.borrow().opaque;
138-
has_dtor |= ci.borrow().has_destructor;
139-
module_id = ci.borrow().module_id;
140-
}
141-
_ => {}
142-
}
133+
ci.ref_template = Some(parent.clone().to_type())
143134
}
144135

145-
let mut ci = CompInfo::new(spelling, module_id, filename, comment, kind, vec![], layout);
146136
ci.opaque = opaque;
147137
ci.hide = hide;
148138
ci.args = args;
149-
ci.has_destructor = has_dtor;
150139
ci.has_non_type_template_params = has_non_type_template_params;
151140

152141
let ci = Rc::new(RefCell::new(ci));
@@ -365,16 +354,12 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
365354
list
366355
}
367356
};
357+
368358
let ci = decl.compinfo();
359+
// NB: Args might be filled from decl_name,
360+
// it's important not to override
369361
if !args.is_empty() {
370362
ci.borrow_mut().args = args;
371-
cursor.visit(|c, _: &Cursor| {
372-
if c.kind() == CXCursor_TemplateRef {
373-
let decl = decl_name(ctx, &c.referenced());
374-
ci.borrow_mut().ref_template = Some(decl.to_type());
375-
}
376-
CXChildVisit_Continue
377-
});
378363
}
379364

380365
TComp(ci)
@@ -859,6 +844,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
859844
}
860845
CXCursor_Destructor => {
861846
ci.has_destructor = true;
847+
// Propagate the change to the parent
862848
if let Some(ref t) = ci.ref_template {
863849
match *t {
864850
TComp(ref parent_ci) => parent_ci.borrow_mut().has_destructor = true,

src/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,15 @@ impl CompInfo {
458458
}
459459
}
460460

461+
// Return the module id or the class declaration module id.
462+
pub fn module_id(&self) -> ModuleId {
463+
self.ref_template.as_ref().and_then(|t| if let TComp(ref ci) = *t {
464+
Some(ci.borrow().module_id)
465+
} else {
466+
None
467+
}).unwrap_or(self.module_id)
468+
}
469+
461470
pub fn can_derive_debug(&self) -> bool {
462471
if self.hide || self.is_opaque() {
463472
return false;
@@ -511,6 +520,7 @@ impl CompInfo {
511520
// not having destructor.
512521
//
513522
// This is unfortunate, but...
523+
self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) ||
514524
self.args.iter().any(|t| t.has_destructor()) ||
515525
self.members.iter().enumerate().any(|(index, m)| match *m {
516526
CompMember::Field(ref f) |

tests/expectations/namespace.rs

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,67 @@
55
#![allow(non_snake_case)]
66

77

8-
pub type whatever_int_t = ::std::os::raw::c_int;
9-
#[repr(C)]
10-
#[derive(Debug, Copy)]
11-
pub struct Struct_A {
12-
pub b: whatever_int_t,
13-
}
14-
impl ::std::clone::Clone for Struct_A {
15-
fn clone(&self) -> Self { *self }
16-
}
17-
#[test]
18-
fn bindgen_test_layout_Struct_A() {
19-
assert_eq!(::std::mem::size_of::<Struct_A>() , 4usize);
20-
assert_eq!(::std::mem::align_of::<Struct_A>() , 4usize);
21-
}
22-
#[repr(C)]
23-
#[derive(Debug)]
24-
pub struct Struct_C<T> {
25-
pub _base: Struct_A,
26-
pub m_c: T,
27-
pub m_c_ptr: *mut T,
28-
pub m_c_arr: [T; 10usize],
29-
}
30-
#[repr(C)]
31-
#[derive(Debug)]
32-
pub struct Struct_D<T> {
33-
pub m_c: Struct_C<T>,
34-
pub _phantom0: ::std::marker::PhantomData<T>,
35-
}
36-
extern "C" {
37-
#[link_name = "_Z9top_levelv"]
38-
pub fn top_level();
39-
#[link_name = "_ZN8whatever11in_whateverEv"]
40-
pub fn in_whatever();
41-
#[link_name = "_ZN12_GLOBAL__N_13fooEv"]
42-
pub fn foo();
43-
#[link_name = "_ZN1w3hehEv"]
44-
pub fn heh() -> whatever_int_t;
45-
#[link_name = "_ZN1w3fooEv"]
46-
pub fn foo1() -> Struct_C<::std::os::raw::c_int>;
47-
#[link_name = "_ZN1w4barrEv"]
48-
pub fn barr() -> Struct_C<f32>;
8+
pub use root::*;
9+
pub mod root {
10+
#[repr(C)]
11+
#[derive(Debug)]
12+
pub struct Struct_C<T> {
13+
pub _base: __anonymous1::Struct_A,
14+
pub m_c: T,
15+
pub m_c_ptr: *mut T,
16+
pub m_c_arr: [T; 10usize],
17+
}
18+
extern "C" {
19+
#[link_name = "_Z9top_levelv"]
20+
pub fn top_level();
21+
}
22+
pub mod whatever {
23+
use root;
24+
pub type whatever_int_t = ::std::os::raw::c_int;
25+
extern "C" {
26+
#[link_name = "_ZN8whatever11in_whateverEv"]
27+
pub fn in_whatever();
28+
}
29+
}
30+
pub mod __anonymous1 {
31+
use root;
32+
#[repr(C)]
33+
#[derive(Debug, Copy)]
34+
pub struct Struct_A {
35+
pub b: root::whatever::whatever_int_t,
36+
}
37+
impl ::std::clone::Clone for Struct_A {
38+
fn clone(&self) -> Self { *self }
39+
}
40+
#[test]
41+
fn bindgen_test_layout_Struct_A() {
42+
assert_eq!(::std::mem::size_of::<Struct_A>() , 4usize);
43+
assert_eq!(::std::mem::align_of::<Struct_A>() , 4usize);
44+
}
45+
extern "C" {
46+
#[link_name = "_ZN12_GLOBAL__N_13fooEv"]
47+
pub fn foo();
48+
}
49+
pub mod empty {
50+
use root;
51+
}
52+
}
53+
pub mod w {
54+
use root;
55+
pub type whatever_int_t = ::std::os::raw::c_uint;
56+
#[repr(C)]
57+
#[derive(Debug)]
58+
pub struct Struct_D<T> {
59+
pub m_c: root::Struct_C<T>,
60+
pub _phantom0: ::std::marker::PhantomData<T>,
61+
}
62+
extern "C" {
63+
#[link_name = "_ZN1w3hehEv"]
64+
pub fn heh() -> root::w::whatever_int_t;
65+
#[link_name = "_ZN1w3fooEv"]
66+
pub fn foo() -> root::Struct_C<::std::os::raw::c_int>;
67+
#[link_name = "_ZN1w4barrEv"]
68+
pub fn barr() -> root::Struct_C<f32>;
69+
}
70+
}
4971
}

tests/expectations/template.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct Struct_D_U<T, Z> {
3131
#[derive(Debug, Copy, Clone)]
3232
pub struct Struct_Rooted<T> {
3333
pub prev: *mut T,
34-
pub next: *mut T,
34+
pub next: *mut Struct_Rooted<*mut ::std::os::raw::c_void>,
3535
pub ptr: T,
3636
}
3737
#[repr(C)]

tests/headers/namespace.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
// bindgen-flags: -enable-cxx-namespaces
22

33
void top_level();
44

tests/headers/template.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class D {
2222
template<typename T>
2323
class Rooted {
2424
T* prev;
25-
T* next;
25+
Rooted<void*>* next;
2626
T ptr;
2727
};
2828

0 commit comments

Comments
 (0)