summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Taylor <ade@hohum.me.uk>2021-10-03 09:35:10 -0700
committerEmilio Cobos Álvarez <emilio@crisal.io>2021-10-27 19:23:31 +0200
commitda3f3a3ab13fb335b525d74a38e6a8634a117fe5 (patch)
tree818c72154e1969c1f093fa06e00b831e87830449
parent57853405463dd985dd49a2f14fb78bbf3595b1df (diff)
Avoid case of a self-referential type alias.
This previously produced a type alias which referred to itself, which was clearly wrong and resulted in downstream code recursing infinitely. The problem case (per bug #2102) is: template <typename> class B{}; template <typename c> class C { public: using U = B<c>; }; class A : C<A> { U u; }; As far as I can tell, we parse clang's definition of B<A>; that leads us to parse A; to find it has a field U which turns out to be of type B<A>. And so we hit the line in item.rs which says: debug!("Avoiding recursion parsing type: {:?}", ty); and bail out, returning the original item ID: hence, a self- referential typedef is created. The 'fix' in this PR creates an opaque type in this case instead, to avoid later infinite loops. It would be preferable to avoid this situation in the first place, but presumably that would require us to split the parsing phase into two: 1) types 2) fields within those types. Fixes #2102.
-rw-r--r--src/ir/ty.rs11
-rw-r--r--tests/expectations/tests/constified-enum-module-overflow.rs54
-rw-r--r--tests/headers/constified-enum-module-overflow.hpp8
3 files changed, 72 insertions, 1 deletions
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 9cfbd7a9..d573408c 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -1082,7 +1082,16 @@ impl Type {
let inner = cursor.typedef_type().expect("Not valid Type?");
let inner =
Item::from_ty_or_ref(inner, location, None, ctx);
- TypeKind::Alias(inner)
+ if inner == potential_id {
+ warn!(
+ "Generating oqaque type instead of self-referential \
+ typedef");
+ // This can happen if we bail out of recursive situations
+ // within the clang parsing.
+ TypeKind::Opaque
+ } else {
+ TypeKind::Alias(inner)
+ }
}
CXType_Enum => {
let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
diff --git a/tests/expectations/tests/constified-enum-module-overflow.rs b/tests/expectations/tests/constified-enum-module-overflow.rs
new file mode 100644
index 00000000..4a799ef8
--- /dev/null
+++ b/tests/expectations/tests/constified-enum-module-overflow.rs
@@ -0,0 +1,54 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct B {
+ pub _address: u8,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct C {
+ pub _address: u8,
+}
+pub type C_U = B;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct A {
+ pub u: u8,
+}
+#[test]
+fn bindgen_test_layout_A() {
+ assert_eq!(
+ ::std::mem::size_of::<A>(),
+ 1usize,
+ concat!("Size of: ", stringify!(A))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<A>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(A))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<A>())).u as *const _ as usize },
+ 0usize,
+ concat!("Offset of field: ", stringify!(A), "::", stringify!(u))
+ );
+}
+#[test]
+fn __bindgen_test_layout_C_open0_A_close0_instantiation() {
+ assert_eq!(
+ ::std::mem::size_of::<C>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(C))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<C>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(C))
+ );
+}
diff --git a/tests/headers/constified-enum-module-overflow.hpp b/tests/headers/constified-enum-module-overflow.hpp
new file mode 100644
index 00000000..d48f2be1
--- /dev/null
+++ b/tests/headers/constified-enum-module-overflow.hpp
@@ -0,0 +1,8 @@
+template <typename> class B{};
+template <typename c> class C {
+public:
+ using U = B<c>;
+};
+class A : C<A> {
+ U u;
+};