@@ -233,37 +233,14 @@ impl<'a> TypeConverter<'a> {
233
233
ctx : & TypeConversionContext ,
234
234
) -> Result < Annotated < Type > , ConvertErrorFromCpp > {
235
235
// First, qualify any unqualified paths.
236
- if typ. path . segments . iter ( ) . next ( ) . unwrap ( ) . ident != "root" {
237
- let ty = QualifiedName :: from_type_path ( & typ) ;
238
- // If the type looks like it is unqualified, check we know it
239
- // already, and if not, qualify it according to the current
240
- // namespace. This is a bit of a shortcut compared to having a full
241
- // resolution pass which can search all known namespaces.
242
- if !known_types ( ) . is_known_type ( & ty) {
243
- let num_segments = typ. path . segments . len ( ) ;
244
- if num_segments > 1 {
245
- return Err ( ConvertErrorFromCpp :: UnsupportedBuiltInType ( ty) ) ;
246
- }
247
- if !self . types_found . contains ( & ty) {
248
- typ. path . segments = std:: iter:: once ( & "root" . to_string ( ) )
249
- . chain ( ns. iter ( ) )
250
- . map ( |s| {
251
- let i = make_ident ( s) ;
252
- parse_quote ! { #i }
253
- } )
254
- . chain ( typ. path . segments )
255
- . collect ( ) ;
256
- }
257
- }
258
- }
259
-
260
- let original_tn = QualifiedName :: from_type_path ( & typ) ;
236
+ let original_tn = self . qualified_name_from_bindgen_output_type_path ( & mut typ, ns) ?;
261
237
original_tn
262
238
. validate_ok_for_cxx ( )
263
239
. map_err ( ConvertErrorFromCpp :: InvalidIdent ) ?;
264
240
if self . config . is_on_blocklist ( & original_tn. to_cpp_name ( ) ) {
265
241
return Err ( ConvertErrorFromCpp :: Blocked ( original_tn) ) ;
266
242
}
243
+
267
244
let mut deps = HashSet :: new ( ) ;
268
245
269
246
// Now convert this type itself.
@@ -370,7 +347,7 @@ impl<'a> TypeConverter<'a> {
370
347
if self . ignored_types . contains ( & qn) {
371
348
return Err ( ConvertErrorFromCpp :: ConcreteVersionOfIgnoredTemplate ) ;
372
349
}
373
- let ( new_tn, api) = self . get_templated_typename ( & Type :: Path ( typ) ) ?;
350
+ let ( new_tn, api) = self . get_templated_typename ( & Type :: Path ( typ) , & qn , ns ) ?;
374
351
extra_apis. extend ( api. into_iter ( ) ) ;
375
352
// Although it's tempting to remove the dep on the original type,
376
353
// this means we wouldn't spot cases where the original type can't
@@ -383,13 +360,87 @@ impl<'a> TypeConverter<'a> {
383
360
Ok ( Annotated :: new ( Type :: Path ( typ) , deps, extra_apis, kind) )
384
361
}
385
362
363
+ fn qualified_name_from_bindgen_output_type_path (
364
+ & self ,
365
+ typ : & mut TypePath ,
366
+ ns : & Namespace ,
367
+ ) -> Result < QualifiedName , ConvertErrorFromCpp > {
368
+ if typ. path . segments . iter ( ) . next ( ) . unwrap ( ) . ident != "root" {
369
+ let ty = QualifiedName :: from_type_path ( & typ) ;
370
+ // If the type looks like it is unqualified, check we know it
371
+ // already, and if not, qualify it according to the current
372
+ // namespace. This is a bit of a shortcut compared to having a full
373
+ // resolution pass which can search all known namespaces.
374
+ if !known_types ( ) . is_known_type ( & ty) {
375
+ let num_segments = typ. path . segments . len ( ) ;
376
+ if num_segments > 1 {
377
+ return Err ( ConvertErrorFromCpp :: UnsupportedBuiltInType ( ty) ) ;
378
+ }
379
+ if !self . types_found . contains ( & ty) {
380
+ typ. path . segments = std:: iter:: once ( & "root" . to_string ( ) )
381
+ . chain ( ns. iter ( ) )
382
+ . map ( |s| {
383
+ let i = make_ident ( s) ;
384
+ parse_quote ! { #i }
385
+ } )
386
+ . chain ( typ. path . segments . clone ( ) )
387
+ . collect ( ) ;
388
+ }
389
+ }
390
+ }
391
+
392
+ Ok ( QualifiedName :: from_type_path ( & typ) )
393
+ }
394
+
386
395
fn get_generic_args ( typ : & mut TypePath ) -> Option < & mut PathSegment > {
387
396
match typ. path . segments . last_mut ( ) {
388
397
Some ( s) if !s. arguments . is_empty ( ) => Some ( s) ,
389
398
_ => None ,
390
399
}
391
400
}
392
401
402
+ fn type_params_depend_on_forward_declarations ( & self , ty : & Type , ns : & Namespace ) -> bool {
403
+ if let Type :: Path ( typ) = ty {
404
+ let type_params = self . get_type_params ( & mut typ. clone ( ) , ns) ;
405
+ !type_params. is_disjoint ( & self . forward_declarations )
406
+ } else {
407
+ false // FIXME do better
408
+ }
409
+ }
410
+
411
+ /// Get the names of any type parameters in this type path.
412
+ fn get_type_params ( & self , typ : & mut TypePath , ns : & Namespace ) -> HashSet < QualifiedName > {
413
+ typ. path
414
+ . segments
415
+ . iter_mut ( )
416
+ . map ( |seg| match seg. arguments {
417
+ PathArguments :: AngleBracketed ( ref mut angle_bracketed_generic_arguments) => {
418
+ Box :: new (
419
+ angle_bracketed_generic_arguments
420
+ . args
421
+ . iter_mut ( )
422
+ . filter_map ( |arg| match arg {
423
+ GenericArgument :: Type ( Type :: Path ( ref mut inner_typ) ) => {
424
+ // Disregard any errors during this process, for now.
425
+ // We are looking for types which we have previously
426
+ // recorded as forward declarations. If we can't
427
+ // figure out the name of this type now, we probably
428
+ // couldn't have done so in the past when we
429
+ // recorded it as a forward declaration, so it wouldn't
430
+ // have matched anyway.
431
+ self . qualified_name_from_bindgen_output_type_path ( inner_typ, ns)
432
+ . ok ( )
433
+ }
434
+ _ => None ,
435
+ } ) ,
436
+ ) as Box < dyn Iterator < Item = QualifiedName > >
437
+ }
438
+ _ => Box :: new ( std:: iter:: empty ( ) ) as Box < dyn Iterator < Item = QualifiedName > > ,
439
+ } )
440
+ . flatten ( )
441
+ . collect ( )
442
+ }
443
+
393
444
fn convert_punctuated < P > (
394
445
& mut self ,
395
446
pun : Punctuated < GenericArgument , P > ,
@@ -525,6 +576,8 @@ impl<'a> TypeConverter<'a> {
525
576
fn get_templated_typename (
526
577
& mut self ,
527
578
rs_definition : & Type ,
579
+ qn : & QualifiedName ,
580
+ ns : & Namespace ,
528
581
) -> Result < ( QualifiedName , Option < UnanalyzedApi > ) , ConvertErrorFromCpp > {
529
582
let count = self . concrete_templates . len ( ) ;
530
583
// We just use this as a hash key, essentially.
@@ -556,10 +609,13 @@ impl<'a> TypeConverter<'a> {
556
609
None => synthetic_ident,
557
610
Some ( _) => format ! ( "AutocxxConcrete{count}" ) ,
558
611
} ;
612
+
613
+ let depends_on_forward_declaration = self . forward_declarations . contains ( qn) || self . type_params_depend_on_forward_declarations ( & rs_definition, ns) ;
559
614
let api = UnanalyzedApi :: ConcreteType {
560
615
name : ApiName :: new_in_root_namespace ( make_ident ( synthetic_ident) ) ,
561
616
cpp_definition : cpp_definition. clone ( ) ,
562
617
rs_definition : Some ( Box :: new ( rs_definition. clone ( ) . into ( ) ) ) ,
618
+ depends_on_forward_declaration,
563
619
} ;
564
620
self . concrete_templates
565
621
. insert ( cpp_definition, api. name ( ) . clone ( ) ) ;
@@ -670,6 +726,10 @@ impl<'a> TypeConverter<'a> {
670
726
| Api :: OpaqueTypedef {
671
727
forward_declaration : true ,
672
728
..
729
+ }
730
+ | Api :: ConcreteType {
731
+ depends_on_forward_declaration : true ,
732
+ ..
673
733
} => Some ( api. name ( ) ) ,
674
734
_ => None ,
675
735
} )
@@ -699,10 +759,12 @@ pub(crate) fn add_analysis<A: AnalysisPhase>(api: UnanalyzedApi) -> Api<A> {
699
759
name,
700
760
rs_definition,
701
761
cpp_definition,
762
+ depends_on_forward_declaration,
702
763
} => Api :: ConcreteType {
703
764
name,
704
765
rs_definition,
705
766
cpp_definition,
767
+ depends_on_forward_declaration,
706
768
} ,
707
769
Api :: IgnoredItem { name, err, ctx } => Api :: IgnoredItem { name, err, ctx } ,
708
770
_ => panic ! ( "Function analysis created an unexpected type of extra API" ) ,
0 commit comments