summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/item.rs4
-rw-r--r--tests/expectations/tests/canonical-types.rs278
-rw-r--r--tests/expectations/tests/layout_cmdline_token.rs2
-rw-r--r--tests/headers/canonical-types.hpp51
4 files changed, 333 insertions, 2 deletions
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 4e0ba80b..a38c8e5f 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -1594,8 +1594,8 @@ impl ClangItemParser for Item {
}
let decl = {
- let decl = ty.declaration();
- decl.definition().unwrap_or(decl)
+ let canonical_def = ty.canonical_type().declaration().definition();
+ canonical_def.unwrap_or_else(|| ty.declaration())
};
let comment = decl.raw_comment().or_else(|| location.raw_comment());
diff --git a/tests/expectations/tests/canonical-types.rs b/tests/expectations/tests/canonical-types.rs
new file mode 100644
index 00000000..80d7fec3
--- /dev/null
+++ b/tests/expectations/tests/canonical-types.rs
@@ -0,0 +1,278 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ClassA {
+ pub _address: u8,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassA_ClassAInner<T> {
+ pub x: *mut T,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+}
+impl<T> Default for ClassA_ClassAInner<T> {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ClassB {
+ pub _address: u8,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ClassC {
+ pub _address: u8,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassC_ClassCInnerB {
+ pub cache: *mut ClassC_ClassCInnerA,
+}
+impl Default for ClassC_ClassCInnerB {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassC_ClassCInnerA {
+ pub member: *mut ClassC_ClassCInnerB,
+}
+impl Default for ClassC_ClassCInnerA {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassC_ClassCInnerCRTP {
+ pub _address: u8,
+}
+impl Default for ClassC_ClassCInnerCRTP {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassD {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_ClassD() {
+ assert_eq!(
+ ::std::mem::size_of::<ClassD>(),
+ 1usize,
+ concat!("Size of: ", stringify!(ClassD))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassD>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(ClassD))
+ );
+}
+impl Default for ClassD {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[test]
+fn __bindgen_test_layout_ClassB_open0_ClassD_ClassCInnerCRTP_close0_instantiation(
+) {
+ assert_eq!(
+ ::std::mem::size_of::<ClassB>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(ClassB))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassB>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(ClassB))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassCInnerCRTP {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_ClassCInnerCRTP() {
+ assert_eq!(
+ ::std::mem::size_of::<ClassCInnerCRTP>(),
+ 1usize,
+ concat!("Size of: ", stringify!(ClassCInnerCRTP))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassCInnerCRTP>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(ClassCInnerCRTP))
+ );
+}
+impl Default for ClassCInnerCRTP {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[test]
+fn __bindgen_test_layout_ClassB_open0_ClassCInnerCRTP_ClassAInner_close0_instantiation(
+) {
+ assert_eq!(
+ ::std::mem::size_of::<ClassB>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(ClassB))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassB>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(ClassB))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassAInner {
+ pub x: *mut ClassCInnerA,
+}
+#[test]
+fn bindgen_test_layout_ClassAInner() {
+ assert_eq!(
+ ::std::mem::size_of::<ClassAInner>(),
+ 8usize,
+ concat!("Size of: ", stringify!(ClassAInner))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassAInner>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(ClassAInner))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<ClassAInner>())).x as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(ClassAInner),
+ "::",
+ stringify!(x)
+ )
+ );
+}
+impl Default for ClassAInner {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassCInnerA {
+ pub member: *mut ClassCInnerB,
+}
+#[test]
+fn bindgen_test_layout_ClassCInnerA() {
+ assert_eq!(
+ ::std::mem::size_of::<ClassCInnerA>(),
+ 8usize,
+ concat!("Size of: ", stringify!(ClassCInnerA))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassCInnerA>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(ClassCInnerA))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<ClassCInnerA>())).member as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(ClassCInnerA),
+ "::",
+ stringify!(member)
+ )
+ );
+}
+impl Default for ClassCInnerA {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ClassCInnerB {
+ pub cache: *mut ClassCInnerA,
+}
+#[test]
+fn bindgen_test_layout_ClassCInnerB() {
+ assert_eq!(
+ ::std::mem::size_of::<ClassCInnerB>(),
+ 8usize,
+ concat!("Size of: ", stringify!(ClassCInnerB))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<ClassCInnerB>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(ClassCInnerB))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<ClassCInnerB>())).cache as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(ClassCInnerB),
+ "::",
+ stringify!(cache)
+ )
+ );
+}
+impl Default for ClassCInnerB {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
diff --git a/tests/expectations/tests/layout_cmdline_token.rs b/tests/expectations/tests/layout_cmdline_token.rs
index 644b1b8a..47170dd7 100644
--- a/tests/expectations/tests/layout_cmdline_token.rs
+++ b/tests/expectations/tests/layout_cmdline_token.rs
@@ -61,6 +61,8 @@ impl Default for cmdline_token_hdr {
}
}
}
+/// Stores a pointer to the ops struct, and the offset: the place to
+/// write the parsed result in the destination structure.
pub type cmdline_parse_token_hdr_t = cmdline_token_hdr;
/// A token is defined by this structure.
///
diff --git a/tests/headers/canonical-types.hpp b/tests/headers/canonical-types.hpp
new file mode 100644
index 00000000..c8eadd7e
--- /dev/null
+++ b/tests/headers/canonical-types.hpp
@@ -0,0 +1,51 @@
+// bindgen-flags: -- -std=c++14
+
+// Issue #2078. To pick up the definition of `ClassCInnerA`,
+// `ty.canonical_type().declaration().definition()` is needed.
+
+template<class T>
+class ClassA {
+public:
+ class ClassAInner {
+ public:
+ T *x;
+ };
+};
+
+template<class D, class I>
+class ClassB {
+public:
+ void foo() {
+ ((D *)0)->quux();
+ }
+};
+
+template<typename T>
+class ClassC {
+ struct ClassCInnerA;
+
+ struct ClassCInnerB {
+ ClassCInnerA *cache;
+ };
+ static_assert(sizeof(ClassCInnerB) > 0, "");
+
+ struct ClassCInnerA {
+ ClassCInnerB *member;
+ };
+
+public:
+ class ClassCInnerCRTP : public ClassB<ClassCInnerCRTP, typename ClassA<ClassCInnerA>::ClassAInner> {
+ public:
+ void quux() {
+ ((typename ClassA<ClassCInnerA>::ClassAInner *)0)->x->member;
+ }
+ };
+};
+
+class ClassD : public ClassB<ClassD, ClassC<int>::ClassCInnerCRTP> {
+public:
+ void bar() {
+ ((ClassC<int>::ClassCInnerCRTP *)0)->foo();
+ }
+};
+