Skip to content

Commit df998e1

Browse files
adetaylorlightsofapollo
authored andcommitted
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 rust-lang#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 rust-lang#2102.
1 parent e825b46 commit df998e1

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

src/ir/ty.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,16 @@ impl Type {
11201120
let inner = cursor.typedef_type().expect("Not valid Type?");
11211121
let inner =
11221122
Item::from_ty_or_ref(inner, location, None, ctx);
1123-
TypeKind::Alias(inner)
1123+
if inner == potential_id {
1124+
warn!(
1125+
"Generating oqaque type instead of self-referential \
1126+
typedef");
1127+
// This can happen if we bail out of recursive situations
1128+
// within the clang parsing.
1129+
TypeKind::Opaque
1130+
} else {
1131+
TypeKind::Alias(inner)
1132+
}
11241133
}
11251134
CXType_Enum => {
11261135
let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
#[repr(C)]
9+
#[derive(Debug, Default, Copy, Clone)]
10+
pub struct B {
11+
pub _address: u8,
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Default, Copy, Clone)]
15+
pub struct C {
16+
pub _address: u8,
17+
}
18+
pub type C_U = B;
19+
#[repr(C)]
20+
#[derive(Debug, Default, Copy, Clone)]
21+
pub struct A {
22+
pub u: u8,
23+
}
24+
#[test]
25+
fn bindgen_test_layout_A() {
26+
assert_eq!(
27+
::std::mem::size_of::<A>(),
28+
1usize,
29+
concat!("Size of: ", stringify!(A))
30+
);
31+
assert_eq!(
32+
::std::mem::align_of::<A>(),
33+
1usize,
34+
concat!("Alignment of ", stringify!(A))
35+
);
36+
assert_eq!(
37+
unsafe { &(*(::std::ptr::null::<A>())).u as *const _ as usize },
38+
0usize,
39+
concat!("Offset of field: ", stringify!(A), "::", stringify!(u))
40+
);
41+
}
42+
#[test]
43+
fn __bindgen_test_layout_C_open0_A_close0_instantiation() {
44+
assert_eq!(
45+
::std::mem::size_of::<C>(),
46+
1usize,
47+
concat!("Size of template specialization: ", stringify!(C))
48+
);
49+
assert_eq!(
50+
::std::mem::align_of::<C>(),
51+
1usize,
52+
concat!("Alignment of template specialization: ", stringify!(C))
53+
);
54+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
template <typename> class B{};
2+
template <typename c> class C {
3+
public:
4+
using U = B<c>;
5+
};
6+
class A : C<A> {
7+
U u;
8+
};

0 commit comments

Comments
 (0)