Skip to content

Commit c6cc0aa

Browse files
committed
Canonicalize types before looking for their definitions.
In some esoteric cases involving nested templates, `ty.declaration().definition()` isn't enough to find the definition: we need `ty.canonical_type().declaration().definition()` instead. Closes rust-lang#2078.
1 parent e05a451 commit c6cc0aa

File tree

3 files changed

+330
-1
lines changed

3 files changed

+330
-1
lines changed

src/ir/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,7 @@ impl ClangItemParser for Item {
15941594
}
15951595

15961596
let decl = {
1597-
let decl = ty.declaration();
1597+
let decl = ty.canonical_type().declaration();
15981598
decl.definition().unwrap_or(decl)
15991599
};
16001600

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
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 ClassA {
11+
pub _address: u8,
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Copy, Clone)]
15+
pub struct ClassA_ClassAInner<T> {
16+
pub x: *mut T,
17+
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
18+
}
19+
impl<T> Default for ClassA_ClassAInner<T> {
20+
fn default() -> Self {
21+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
22+
unsafe {
23+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
24+
s.assume_init()
25+
}
26+
}
27+
}
28+
#[repr(C)]
29+
#[derive(Debug, Default, Copy, Clone)]
30+
pub struct ClassB {
31+
pub _address: u8,
32+
}
33+
#[repr(C)]
34+
#[derive(Debug, Default, Copy, Clone)]
35+
pub struct ClassC {
36+
pub _address: u8,
37+
}
38+
#[repr(C)]
39+
#[derive(Debug, Copy, Clone)]
40+
pub struct ClassC_ClassCInnerB {
41+
pub cache: *mut ClassC_ClassCInnerA,
42+
}
43+
impl Default for ClassC_ClassCInnerB {
44+
fn default() -> Self {
45+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
46+
unsafe {
47+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
48+
s.assume_init()
49+
}
50+
}
51+
}
52+
#[repr(C)]
53+
#[derive(Debug, Copy, Clone)]
54+
pub struct ClassC_ClassCInnerA {
55+
pub member: *mut ClassC_ClassCInnerB,
56+
}
57+
impl Default for ClassC_ClassCInnerA {
58+
fn default() -> Self {
59+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
60+
unsafe {
61+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
62+
s.assume_init()
63+
}
64+
}
65+
}
66+
#[repr(C)]
67+
#[derive(Debug, Copy, Clone)]
68+
pub struct ClassC_ClassCInnerCRTP {
69+
pub _address: u8,
70+
}
71+
impl Default for ClassC_ClassCInnerCRTP {
72+
fn default() -> Self {
73+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
74+
unsafe {
75+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
76+
s.assume_init()
77+
}
78+
}
79+
}
80+
#[repr(C)]
81+
#[derive(Debug, Copy, Clone)]
82+
pub struct ClassD {
83+
pub _address: u8,
84+
}
85+
#[test]
86+
fn bindgen_test_layout_ClassD() {
87+
assert_eq!(
88+
::std::mem::size_of::<ClassD>(),
89+
1usize,
90+
concat!("Size of: ", stringify!(ClassD))
91+
);
92+
assert_eq!(
93+
::std::mem::align_of::<ClassD>(),
94+
1usize,
95+
concat!("Alignment of ", stringify!(ClassD))
96+
);
97+
}
98+
impl Default for ClassD {
99+
fn default() -> Self {
100+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
101+
unsafe {
102+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
103+
s.assume_init()
104+
}
105+
}
106+
}
107+
#[test]
108+
fn __bindgen_test_layout_ClassB_open0_ClassD_ClassCInnerCRTP_close0_instantiation(
109+
) {
110+
assert_eq!(
111+
::std::mem::size_of::<ClassB>(),
112+
1usize,
113+
concat!("Size of template specialization: ", stringify!(ClassB))
114+
);
115+
assert_eq!(
116+
::std::mem::align_of::<ClassB>(),
117+
1usize,
118+
concat!("Alignment of template specialization: ", stringify!(ClassB))
119+
);
120+
}
121+
#[repr(C)]
122+
#[derive(Debug, Copy, Clone)]
123+
pub struct ClassCInnerCRTP {
124+
pub _address: u8,
125+
}
126+
#[test]
127+
fn bindgen_test_layout_ClassCInnerCRTP() {
128+
assert_eq!(
129+
::std::mem::size_of::<ClassCInnerCRTP>(),
130+
1usize,
131+
concat!("Size of: ", stringify!(ClassCInnerCRTP))
132+
);
133+
assert_eq!(
134+
::std::mem::align_of::<ClassCInnerCRTP>(),
135+
1usize,
136+
concat!("Alignment of ", stringify!(ClassCInnerCRTP))
137+
);
138+
}
139+
impl Default for ClassCInnerCRTP {
140+
fn default() -> Self {
141+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
142+
unsafe {
143+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
144+
s.assume_init()
145+
}
146+
}
147+
}
148+
#[test]
149+
fn __bindgen_test_layout_ClassB_open0_ClassCInnerCRTP_ClassAInner_close0_instantiation(
150+
) {
151+
assert_eq!(
152+
::std::mem::size_of::<ClassB>(),
153+
1usize,
154+
concat!("Size of template specialization: ", stringify!(ClassB))
155+
);
156+
assert_eq!(
157+
::std::mem::align_of::<ClassB>(),
158+
1usize,
159+
concat!("Alignment of template specialization: ", stringify!(ClassB))
160+
);
161+
}
162+
#[repr(C)]
163+
#[derive(Debug, Copy, Clone)]
164+
pub struct ClassAInner {
165+
pub x: *mut ClassCInnerA,
166+
}
167+
#[test]
168+
fn bindgen_test_layout_ClassAInner() {
169+
assert_eq!(
170+
::std::mem::size_of::<ClassAInner>(),
171+
8usize,
172+
concat!("Size of: ", stringify!(ClassAInner))
173+
);
174+
assert_eq!(
175+
::std::mem::align_of::<ClassAInner>(),
176+
8usize,
177+
concat!("Alignment of ", stringify!(ClassAInner))
178+
);
179+
assert_eq!(
180+
unsafe {
181+
&(*(::std::ptr::null::<ClassAInner>())).x as *const _ as usize
182+
},
183+
0usize,
184+
concat!(
185+
"Offset of field: ",
186+
stringify!(ClassAInner),
187+
"::",
188+
stringify!(x)
189+
)
190+
);
191+
}
192+
impl Default for ClassAInner {
193+
fn default() -> Self {
194+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
195+
unsafe {
196+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
197+
s.assume_init()
198+
}
199+
}
200+
}
201+
#[repr(C)]
202+
#[derive(Debug, Copy, Clone)]
203+
pub struct ClassCInnerA {
204+
pub member: *mut ClassCInnerB,
205+
}
206+
#[test]
207+
fn bindgen_test_layout_ClassCInnerA() {
208+
assert_eq!(
209+
::std::mem::size_of::<ClassCInnerA>(),
210+
8usize,
211+
concat!("Size of: ", stringify!(ClassCInnerA))
212+
);
213+
assert_eq!(
214+
::std::mem::align_of::<ClassCInnerA>(),
215+
8usize,
216+
concat!("Alignment of ", stringify!(ClassCInnerA))
217+
);
218+
assert_eq!(
219+
unsafe {
220+
&(*(::std::ptr::null::<ClassCInnerA>())).member as *const _ as usize
221+
},
222+
0usize,
223+
concat!(
224+
"Offset of field: ",
225+
stringify!(ClassCInnerA),
226+
"::",
227+
stringify!(member)
228+
)
229+
);
230+
}
231+
impl Default for ClassCInnerA {
232+
fn default() -> Self {
233+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
234+
unsafe {
235+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
236+
s.assume_init()
237+
}
238+
}
239+
}
240+
#[repr(C)]
241+
#[derive(Debug, Copy, Clone)]
242+
pub struct ClassCInnerB {
243+
pub cache: *mut ClassCInnerA,
244+
}
245+
#[test]
246+
fn bindgen_test_layout_ClassCInnerB() {
247+
assert_eq!(
248+
::std::mem::size_of::<ClassCInnerB>(),
249+
8usize,
250+
concat!("Size of: ", stringify!(ClassCInnerB))
251+
);
252+
assert_eq!(
253+
::std::mem::align_of::<ClassCInnerB>(),
254+
8usize,
255+
concat!("Alignment of ", stringify!(ClassCInnerB))
256+
);
257+
assert_eq!(
258+
unsafe {
259+
&(*(::std::ptr::null::<ClassCInnerB>())).cache as *const _ as usize
260+
},
261+
0usize,
262+
concat!(
263+
"Offset of field: ",
264+
stringify!(ClassCInnerB),
265+
"::",
266+
stringify!(cache)
267+
)
268+
);
269+
}
270+
impl Default for ClassCInnerB {
271+
fn default() -> Self {
272+
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
273+
unsafe {
274+
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
275+
s.assume_init()
276+
}
277+
}
278+
}

tests/headers/canonical-types.hpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// bindgen-flags: -- -std=c++14
2+
3+
// Issue #2078. To pick up the definition of `ClassCInnerA`,
4+
// `ty.canonical_type().declaration().definition()` is needed.
5+
6+
template<class T>
7+
class ClassA {
8+
public:
9+
class ClassAInner {
10+
public:
11+
T *x;
12+
};
13+
};
14+
15+
template<class D, class I>
16+
class ClassB {
17+
public:
18+
void foo() {
19+
((D *)0)->quux();
20+
}
21+
};
22+
23+
template<typename T>
24+
class ClassC {
25+
struct ClassCInnerA;
26+
27+
struct ClassCInnerB {
28+
ClassCInnerA *cache;
29+
};
30+
static_assert(sizeof(ClassCInnerB) > 0, "");
31+
32+
struct ClassCInnerA {
33+
ClassCInnerB *member;
34+
};
35+
36+
public:
37+
class ClassCInnerCRTP : public ClassB<ClassCInnerCRTP, typename ClassA<ClassCInnerA>::ClassAInner> {
38+
public:
39+
void quux() {
40+
((typename ClassA<ClassCInnerA>::ClassAInner *)0)->x->member;
41+
}
42+
};
43+
};
44+
45+
class ClassD : public ClassB<ClassD, ClassC<int>::ClassCInnerCRTP> {
46+
public:
47+
void bar() {
48+
((ClassC<int>::ClassCInnerCRTP *)0)->foo();
49+
}
50+
};
51+

0 commit comments

Comments
 (0)