@@ -14,6 +14,18 @@ use syntax::ext::base::ExtCtxt;
14
14
use parse:: ClangItemParser ;
15
15
use BindgenOptions ;
16
16
17
+ /// A key used to index a resolved type, so we only process it once.
18
+ ///
19
+ /// This is almost always a USR string (an unique identifier generated by
20
+ /// clang), but it can also be the canonical declaration if the type is unnamed,
21
+ /// in which case clang may generate the same USR for multiple nested unnamed
22
+ /// types.
23
+ #[ derive( Eq , PartialEq , Hash , Debug ) ]
24
+ enum TypeKey {
25
+ USR ( String ) ,
26
+ Declaration ( Cursor ) ,
27
+ }
28
+
17
29
// This is just convenience to avoid creating a manual debug impl for the
18
30
// context.
19
31
struct GenContext < ' ctx > ( ExtCtxt < ' ctx > ) ;
@@ -35,7 +47,7 @@ pub struct BindgenContext<'ctx> {
35
47
36
48
/// Clang USR to type map. This is needed to be able to associate types with
37
49
/// item ids during parsing.
38
- types : HashMap < String , ItemId > ,
50
+ types : HashMap < TypeKey , ItemId > ,
39
51
40
52
/// A cursor to module map. Similar reason than above.
41
53
modules : HashMap < Cursor , ItemId > ,
@@ -129,9 +141,13 @@ impl<'ctx> BindgenContext<'ctx> {
129
141
130
142
let id = item. id ( ) ;
131
143
let is_type = item. kind ( ) . is_type ( ) ;
144
+ let is_unnamed = is_type && item. expect_type ( ) . name ( ) . is_none ( ) ;
132
145
let old_item = self . items . insert ( id, item) ;
133
146
assert ! ( old_item. is_none( ) , "Inserted type twice?" ) ;
134
147
148
+ // Unnamed items can have an USR, but they can't be referenced from
149
+ // other sites explicitly and the USR can match if the unnamed items are
150
+ // nested, so don't bother tracking them.
135
151
if is_type && declaration. is_some ( ) {
136
152
let mut declaration = declaration. unwrap ( ) ;
137
153
if !declaration. is_valid ( ) {
@@ -143,8 +159,6 @@ impl<'ctx> BindgenContext<'ctx> {
143
159
}
144
160
}
145
161
declaration = declaration. canonical ( ) ;
146
-
147
-
148
162
if !declaration. is_valid ( ) {
149
163
// This could happen, for example, with types like `int*` or
150
164
// similar.
@@ -156,12 +170,17 @@ impl<'ctx> BindgenContext<'ctx> {
156
170
return ;
157
171
}
158
172
159
- if let Some ( usr) = declaration. usr ( ) {
160
- let old = self . types . insert ( usr, id) ;
161
- debug_assert_eq ! ( old, None ) ;
173
+ let key = if is_unnamed {
174
+ TypeKey :: Declaration ( declaration)
175
+ } else if let Some ( usr) = declaration. usr ( ) {
176
+ TypeKey :: USR ( usr)
162
177
} else {
163
178
error ! ( "Valid declaration with no USR: {:?}, {:?}" , declaration, location) ;
164
- }
179
+ return ;
180
+ } ;
181
+
182
+ let old = self . types . insert ( key, id) ;
183
+ debug_assert_eq ! ( old, None ) ;
165
184
}
166
185
}
167
186
@@ -503,10 +522,14 @@ impl<'ctx> BindgenContext<'ctx> {
503
522
let canonical_declaration = declaration. canonical ( ) ;
504
523
if canonical_declaration. is_valid ( ) {
505
524
let id =
506
- canonical_declaration
507
- . usr ( )
508
- . and_then ( |usr| self . types . get ( & usr) )
509
- . map ( |id| * id) ;
525
+ self . types . get ( & TypeKey :: Declaration ( canonical_declaration) )
526
+ . map ( |id| * id)
527
+ . or_else ( || {
528
+ canonical_declaration. usr ( ) . and_then ( |usr| {
529
+ self . types . get ( & TypeKey :: USR ( usr) )
530
+ } )
531
+ . map ( |id| * id)
532
+ } ) ;
510
533
if let Some ( id) = id {
511
534
debug ! ( "Already resolved ty {:?}, {:?}, {:?} {:?}" ,
512
535
id, declaration, ty, location) ;
0 commit comments