Skip to content

Commit d4fe3c7

Browse files
committed
Index unnamed types by canonical declaration.
This fixes union_with_nesting.h
1 parent ac89ccf commit d4fe3c7

File tree

3 files changed

+71
-13
lines changed

3 files changed

+71
-13
lines changed

src/ir/context.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ use syntax::ext::base::ExtCtxt;
1414
use parse::ClangItemParser;
1515
use BindgenOptions;
1616

17+
/// A key used to index a resolved type, so we only process it once.
18+
///
19+
/// This is almost always a USR string (an unique identifier generated by
20+
/// clang), but it can also be the canonical declaration if the type is unnamed,
21+
/// in which case clang may generate the same USR for multiple nested unnamed
22+
/// types.
23+
#[derive(Eq, PartialEq, Hash, Debug)]
24+
enum TypeKey {
25+
USR(String),
26+
Declaration(Cursor),
27+
}
28+
1729
// This is just convenience to avoid creating a manual debug impl for the
1830
// context.
1931
struct GenContext<'ctx>(ExtCtxt<'ctx>);
@@ -35,7 +47,7 @@ pub struct BindgenContext<'ctx> {
3547

3648
/// Clang USR to type map. This is needed to be able to associate types with
3749
/// item ids during parsing.
38-
types: HashMap<String, ItemId>,
50+
types: HashMap<TypeKey, ItemId>,
3951

4052
/// A cursor to module map. Similar reason than above.
4153
modules: HashMap<Cursor, ItemId>,
@@ -129,9 +141,13 @@ impl<'ctx> BindgenContext<'ctx> {
129141

130142
let id = item.id();
131143
let is_type = item.kind().is_type();
144+
let is_unnamed = is_type && item.expect_type().name().is_none();
132145
let old_item = self.items.insert(id, item);
133146
assert!(old_item.is_none(), "Inserted type twice?");
134147

148+
// Unnamed items can have an USR, but they can't be referenced from
149+
// other sites explicitly and the USR can match if the unnamed items are
150+
// nested, so don't bother tracking them.
135151
if is_type && declaration.is_some() {
136152
let mut declaration = declaration.unwrap();
137153
if !declaration.is_valid() {
@@ -143,8 +159,6 @@ impl<'ctx> BindgenContext<'ctx> {
143159
}
144160
}
145161
declaration = declaration.canonical();
146-
147-
148162
if !declaration.is_valid() {
149163
// This could happen, for example, with types like `int*` or
150164
// similar.
@@ -156,12 +170,17 @@ impl<'ctx> BindgenContext<'ctx> {
156170
return;
157171
}
158172

159-
if let Some(usr) = declaration.usr() {
160-
let old = self.types.insert(usr, id);
161-
debug_assert_eq!(old, None);
173+
let key = if is_unnamed {
174+
TypeKey::Declaration(declaration)
175+
} else if let Some(usr) = declaration.usr() {
176+
TypeKey::USR(usr)
162177
} else {
163178
error!("Valid declaration with no USR: {:?}, {:?}", declaration, location);
164-
}
179+
return;
180+
};
181+
182+
let old = self.types.insert(key, id);
183+
debug_assert_eq!(old, None);
165184
}
166185
}
167186

@@ -503,10 +522,14 @@ impl<'ctx> BindgenContext<'ctx> {
503522
let canonical_declaration = declaration.canonical();
504523
if canonical_declaration.is_valid() {
505524
let id =
506-
canonical_declaration
507-
.usr()
508-
.and_then(|usr| self.types.get(&usr))
509-
.map(|id| *id);
525+
self.types.get(&TypeKey::Declaration(canonical_declaration))
526+
.map(|id| *id)
527+
.or_else(|| {
528+
canonical_declaration.usr().and_then(|usr| {
529+
self.types.get(&TypeKey::USR(usr))
530+
})
531+
.map(|id| *id)
532+
});
510533
if let Some(id) = id {
511534
debug!("Already resolved ty {:?}, {:?}, {:?} {:?}",
512535
id, declaration, ty, location);

tests/expectations/struct_with_nesting.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct foo {
3535
pub struct foo__bindgen_ty_bindgen_id_4 {
3636
pub b: __BindgenUnionField<::std::os::raw::c_uint>,
3737
pub __bindgen_anon_1: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7>,
38-
pub __bindgen_anon_2: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7>,
38+
pub __bindgen_anon_2: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>,
3939
pub bindgen_union_field: u32,
4040
}
4141
#[repr(C)]
@@ -54,6 +54,24 @@ fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7() {
5454
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7 {
5555
fn clone(&self) -> Self { *self }
5656
}
57+
#[repr(C)]
58+
#[derive(Debug, Copy)]
59+
pub struct foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12 {
60+
pub d1: ::std::os::raw::c_uchar,
61+
pub d2: ::std::os::raw::c_uchar,
62+
pub d3: ::std::os::raw::c_uchar,
63+
pub d4: ::std::os::raw::c_uchar,
64+
}
65+
#[test]
66+
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12() {
67+
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>()
68+
, 4usize);
69+
assert_eq!(::std::mem::align_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>()
70+
, 1usize);
71+
}
72+
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12 {
73+
fn clone(&self) -> Self { *self }
74+
}
5775
#[test]
5876
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4() {
5977
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4>() ,

tests/expectations/union_with_nesting.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct foo {
3535
#[derive(Debug, Copy)]
3636
pub struct foo__bindgen_ty_bindgen_id_4 {
3737
pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5,
38-
pub __bindgen_anon_2: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5,
38+
pub __bindgen_anon_2: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10,
3939
}
4040
#[repr(C)]
4141
#[derive(Debug, Copy)]
@@ -54,6 +54,23 @@ fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5() {
5454
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5 {
5555
fn clone(&self) -> Self { *self }
5656
}
57+
#[repr(C)]
58+
#[derive(Debug, Copy)]
59+
pub struct foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10 {
60+
pub c1: __BindgenUnionField<::std::os::raw::c_ushort>,
61+
pub c2: __BindgenUnionField<::std::os::raw::c_ushort>,
62+
pub bindgen_union_field: u16,
63+
}
64+
#[test]
65+
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10() {
66+
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10>()
67+
, 2usize);
68+
assert_eq!(::std::mem::align_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10>()
69+
, 2usize);
70+
}
71+
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10 {
72+
fn clone(&self) -> Self { *self }
73+
}
5774
#[test]
5875
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4() {
5976
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4>() ,

0 commit comments

Comments
 (0)