summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-09-21 23:16:05 +0200
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-09-21 23:37:14 +0200
commit6ed0253913afc0c0258eaedfb27d87322250f2b2 (patch)
tree336946be39044850a801af21fbff5dfe7cff0449
parent506531522c5910717d89fc3bfdf07d0cdf65485a (diff)
Index unnamed types by canonical declaration.
This fixes union_with_nesting.h
-rw-r--r--src/ir/context.rs45
-rw-r--r--tests/expectations/struct_with_nesting.rs20
-rw-r--r--tests/expectations/union_with_nesting.rs19
3 files changed, 71 insertions, 13 deletions
diff --git a/src/ir/context.rs b/src/ir/context.rs
index f3c24db2..559dd2ba 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -14,6 +14,18 @@ use syntax::ext::base::ExtCtxt;
use parse::ClangItemParser;
use BindgenOptions;
+/// A key used to index a resolved type, so we only process it once.
+///
+/// This is almost always a USR string (an unique identifier generated by
+/// clang), but it can also be the canonical declaration if the type is unnamed,
+/// in which case clang may generate the same USR for multiple nested unnamed
+/// types.
+#[derive(Eq, PartialEq, Hash, Debug)]
+enum TypeKey {
+ USR(String),
+ Declaration(Cursor),
+}
+
// This is just convenience to avoid creating a manual debug impl for the
// context.
struct GenContext<'ctx>(ExtCtxt<'ctx>);
@@ -35,7 +47,7 @@ pub struct BindgenContext<'ctx> {
/// Clang USR to type map. This is needed to be able to associate types with
/// item ids during parsing.
- types: HashMap<String, ItemId>,
+ types: HashMap<TypeKey, ItemId>,
/// A cursor to module map. Similar reason than above.
modules: HashMap<Cursor, ItemId>,
@@ -129,9 +141,13 @@ impl<'ctx> BindgenContext<'ctx> {
let id = item.id();
let is_type = item.kind().is_type();
+ let is_unnamed = is_type && item.expect_type().name().is_none();
let old_item = self.items.insert(id, item);
assert!(old_item.is_none(), "Inserted type twice?");
+ // Unnamed items can have an USR, but they can't be referenced from
+ // other sites explicitly and the USR can match if the unnamed items are
+ // nested, so don't bother tracking them.
if is_type && declaration.is_some() {
let mut declaration = declaration.unwrap();
if !declaration.is_valid() {
@@ -143,8 +159,6 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
declaration = declaration.canonical();
-
-
if !declaration.is_valid() {
// This could happen, for example, with types like `int*` or
// similar.
@@ -156,12 +170,17 @@ impl<'ctx> BindgenContext<'ctx> {
return;
}
- if let Some(usr) = declaration.usr() {
- let old = self.types.insert(usr, id);
- debug_assert_eq!(old, None);
+ let key = if is_unnamed {
+ TypeKey::Declaration(declaration)
+ } else if let Some(usr) = declaration.usr() {
+ TypeKey::USR(usr)
} else {
error!("Valid declaration with no USR: {:?}, {:?}", declaration, location);
- }
+ return;
+ };
+
+ let old = self.types.insert(key, id);
+ debug_assert_eq!(old, None);
}
}
@@ -503,10 +522,14 @@ impl<'ctx> BindgenContext<'ctx> {
let canonical_declaration = declaration.canonical();
if canonical_declaration.is_valid() {
let id =
- canonical_declaration
- .usr()
- .and_then(|usr| self.types.get(&usr))
- .map(|id| *id);
+ self.types.get(&TypeKey::Declaration(canonical_declaration))
+ .map(|id| *id)
+ .or_else(|| {
+ canonical_declaration.usr().and_then(|usr| {
+ self.types.get(&TypeKey::USR(usr))
+ })
+ .map(|id| *id)
+ });
if let Some(id) = id {
debug!("Already resolved ty {:?}, {:?}, {:?} {:?}",
id, declaration, ty, location);
diff --git a/tests/expectations/struct_with_nesting.rs b/tests/expectations/struct_with_nesting.rs
index 75cfecec..9eeeb56e 100644
--- a/tests/expectations/struct_with_nesting.rs
+++ b/tests/expectations/struct_with_nesting.rs
@@ -35,7 +35,7 @@ pub struct foo {
pub struct foo__bindgen_ty_bindgen_id_4 {
pub b: __BindgenUnionField<::std::os::raw::c_uint>,
pub __bindgen_anon_1: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7>,
- pub __bindgen_anon_2: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7>,
+ pub __bindgen_anon_2: __BindgenUnionField<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>,
pub bindgen_union_field: u32,
}
#[repr(C)]
@@ -54,6 +54,24 @@ fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7() {
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_7 {
fn clone(&self) -> Self { *self }
}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12 {
+ pub d1: ::std::os::raw::c_uchar,
+ pub d2: ::std::os::raw::c_uchar,
+ pub d3: ::std::os::raw::c_uchar,
+ pub d4: ::std::os::raw::c_uchar,
+}
+#[test]
+fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12() {
+ assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>()
+ , 4usize);
+ assert_eq!(::std::mem::align_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12>()
+ , 1usize);
+}
+impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_12 {
+ fn clone(&self) -> Self { *self }
+}
#[test]
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4() {
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4>() ,
diff --git a/tests/expectations/union_with_nesting.rs b/tests/expectations/union_with_nesting.rs
index 7534cf81..d7fc780a 100644
--- a/tests/expectations/union_with_nesting.rs
+++ b/tests/expectations/union_with_nesting.rs
@@ -35,7 +35,7 @@ pub struct foo {
#[derive(Debug, Copy)]
pub struct foo__bindgen_ty_bindgen_id_4 {
pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5,
- pub __bindgen_anon_2: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5,
+ pub __bindgen_anon_2: foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10,
}
#[repr(C)]
#[derive(Debug, Copy)]
@@ -54,6 +54,23 @@ fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5() {
impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_5 {
fn clone(&self) -> Self { *self }
}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10 {
+ pub c1: __BindgenUnionField<::std::os::raw::c_ushort>,
+ pub c2: __BindgenUnionField<::std::os::raw::c_ushort>,
+ pub bindgen_union_field: u16,
+}
+#[test]
+fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10() {
+ assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10>()
+ , 2usize);
+ assert_eq!(::std::mem::align_of::<foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10>()
+ , 2usize);
+}
+impl Clone for foo__bindgen_ty_bindgen_id_4__bindgen_ty_bindgen_id_10 {
+ fn clone(&self) -> Self { *self }
+}
#[test]
fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_4() {
assert_eq!(::std::mem::size_of::<foo__bindgen_ty_bindgen_id_4>() ,