Skip to content

Commit 5e41fb9

Browse files
committed
ir: Search for compound structures when we have unexposed type and base class cursor.
And it's not a valid identifier as a template parameter. See the comment and the tests for details.
1 parent b3322dd commit 5e41fb9

11 files changed

+170
-4
lines changed

src/ir/comp.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ impl CompInfo {
635635
ci.has_vtable = cur.is_virtual_base();
636636
}
637637
let type_id =
638-
Item::from_ty(&cur.cur_type(), None, None, ctx)
638+
Item::from_ty(&cur.cur_type(), Some(cur), None, ctx)
639639
.expect("BaseSpecifier");
640640
ci.base_members.push(type_id);
641641
}
@@ -763,6 +763,7 @@ impl CompInfo {
763763
CXCursor_UnionDecl => CompKind::Union,
764764
CXCursor_ClassDecl |
765765
CXCursor_StructDecl => CompKind::Struct,
766+
CXCursor_CXXBaseSpecifier |
766767
CXCursor_ClassTemplatePartialSpecialization |
767768
CXCursor_ClassTemplate => {
768769
match cursor.template_kind() {

src/ir/item.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,7 @@ impl ClangItemParser for Item {
10431043
}
10441044
}
10451045
// If we have recursed into the AST all we know, and we still
1046-
// haven't found what we've got, let's
1047-
// just make a named type.
1046+
// haven't found what we've got, let's just make a named type.
10481047
//
10491048
// This is what happens with some template members, for example.
10501049
//

src/ir/ty.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,56 @@ impl Type {
540540
} else if let Some(location) = location {
541541
match location.kind() {
542542
CXCursor_ClassTemplatePartialSpecialization |
543+
CXCursor_CXXBaseSpecifier |
543544
CXCursor_ClassTemplate => {
544-
name = location.spelling();
545+
if location.kind() == CXCursor_CXXBaseSpecifier {
546+
// In the case we're parsing a base specifier
547+
// inside an unexposed or invalid type, it means
548+
// that we're parsing one of two things:
549+
//
550+
// * A template parameter.
551+
// * A complex class that isn't exposed.
552+
//
553+
// This means, unfortunately, that there's no
554+
// good way to differentiate between them.
555+
//
556+
// Probably we could try to look at the
557+
// declaration and complicate more this logic,
558+
// but we'll keep it simple... if it's a valid
559+
// C++ identifier, we'll consider it as a
560+
// template parameter.
561+
//
562+
// This is because:
563+
//
564+
// * We expect every other base that is a
565+
// proper identifier (that is, a simple
566+
// struct/union declaration), to be exposed,
567+
// so this path can't be reached in that
568+
// case.
569+
//
570+
// * Quite conveniently, complex base
571+
// specifiers preserve their full names (that
572+
// is: Foo<T> instead of Foo). We can take
573+
// advantage of this.
574+
//
575+
// If we find some edge case where this doesn't
576+
// work (which I guess is unlikely, see the
577+
// different test cases[1][2][3][4]), we'd need
578+
// to find more creative ways of differentiating
579+
// these two cases.
580+
//
581+
// [1]: inherit_named.hpp
582+
// [2]: forward-inherit-struct-with-fields.hpp
583+
// [3]: forward-inherit-struct.hpp
584+
// [4]: inherit-namespaced.hpp
585+
if location.spelling()
586+
.chars()
587+
.all(|c| c.is_alphanumeric() || c == '_') {
588+
return Err(ParseError::Recurse);
589+
}
590+
} else {
591+
name = location.spelling();
592+
}
545593
let complex = CompInfo::from_ty(potential_id,
546594
ty,
547595
Some(location),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy, Clone)]
9+
pub struct Rooted<T> {
10+
pub _base: RootedBase<T>,
11+
}
12+
#[repr(C)]
13+
#[derive(Debug, Copy, Clone)]
14+
pub struct RootedBase<T> {
15+
pub foo: *mut T,
16+
pub next: *mut Rooted<T>,
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy, Clone)]
9+
pub struct Rooted<T> {
10+
pub _address: u8,
11+
pub _phantom_0: ::std::marker::PhantomData<T>,
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Copy, Clone)]
15+
pub struct RootedBase<T> {
16+
pub _address: u8,
17+
pub _phantom_0: ::std::marker::PhantomData<T>,
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy, Clone)]
9+
pub struct RootedBase<T> {
10+
pub _address: u8,
11+
pub _phantom_0: ::std::marker::PhantomData<T>,
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Copy, Clone)]
15+
pub struct Rooted<T> {
16+
pub _address: u8,
17+
pub _phantom_0: ::std::marker::PhantomData<T>,
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy)]
9+
pub struct Foo {
10+
pub _address: u8,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Foo() {
14+
assert_eq!(::std::mem::size_of::<Foo>() , 1usize);
15+
assert_eq!(::std::mem::align_of::<Foo>() , 1usize);
16+
}
17+
impl Clone for Foo {
18+
fn clone(&self) -> Self { *self }
19+
}
20+
#[repr(C)]
21+
#[derive(Debug, Copy)]
22+
pub struct Bar {
23+
pub _address: u8,
24+
}
25+
#[test]
26+
fn bindgen_test_layout_Bar() {
27+
assert_eq!(::std::mem::size_of::<Bar>() , 1usize);
28+
assert_eq!(::std::mem::align_of::<Bar>() , 1usize);
29+
}
30+
impl Clone for Bar {
31+
fn clone(&self) -> Self { *self }
32+
}
33+
#[repr(C)]
34+
#[derive(Debug, Copy)]
35+
pub struct Baz {
36+
pub _address: u8,
37+
}
38+
#[test]
39+
fn bindgen_test_layout_Baz() {
40+
assert_eq!(::std::mem::size_of::<Baz>() , 1usize);
41+
assert_eq!(::std::mem::align_of::<Baz>() , 1usize);
42+
}
43+
impl Clone for Baz {
44+
fn clone(&self) -> Self { *self }
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
template <typename> class Rooted;
2+
namespace js {
3+
template <typename T> class RootedBase {
4+
T* foo;
5+
Rooted<T>* next;
6+
};
7+
}
8+
template <typename T> class Rooted : js::RootedBase<T> {};
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
template <typename> class Rooted;
2+
namespace js {
3+
template <typename T> class RootedBase {};
4+
}
5+
template <typename T> class Rooted : js::RootedBase<T> {};

tests/headers/inherit-namespaced.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace js {
2+
template <typename T> class RootedBase {};
3+
}
4+
template <typename T> class Rooted : js::RootedBase<T> {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct Foo {};
2+
struct Bar {};
3+
struct Baz : public Foo, public Bar {};

0 commit comments

Comments
 (0)