127
127
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
128
128
129
129
use super :: context:: { BindgenContext , ItemId } ;
130
- use super :: item:: ItemSet ;
131
- use super :: template:: AsNamed ;
130
+ use super :: item:: { Item , ItemSet } ;
131
+ use super :: template:: { AsNamed , TemplateInstantiation } ;
132
132
use super :: traversal:: { EdgeKind , Trace } ;
133
133
use super :: ty:: { TemplateDeclaration , TypeKind } ;
134
134
use std:: collections:: { HashMap , HashSet } ;
@@ -307,6 +307,103 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
307
307
EdgeKind :: Generic => false ,
308
308
}
309
309
}
310
+
311
+ fn take_this_id_usage_set ( & mut self , this_id : ItemId ) -> ItemSet {
312
+ self . used
313
+ . get_mut ( & this_id)
314
+ . expect ( "Should have a set of used template params for every item \
315
+ id")
316
+ . take ( )
317
+ . expect ( "Should maintain the invariant that all used template param \
318
+ sets are `Some` upon entry of `constrain`")
319
+ }
320
+
321
+ /// We say that blacklisted items use all of their template parameters. The
322
+ /// blacklisted type is most likely implemented explicitly by the user,
323
+ /// since it won't be in the generated bindings, and we don't know exactly
324
+ /// what they'll to with template parameters, but we can push the issue down
325
+ /// the line to them.
326
+ fn constrain_instantiation_of_blacklisted_template ( & self ,
327
+ used_by_this_id : & mut ItemSet ,
328
+ instantiation : & TemplateInstantiation ) {
329
+ debug ! ( " instantiation of blacklisted template, uses all template \
330
+ arguments") ;
331
+
332
+ let args = instantiation. template_arguments ( )
333
+ . iter ( )
334
+ . filter_map ( |a| a. as_named ( self . ctx , & ( ) ) ) ;
335
+ used_by_this_id. extend ( args) ;
336
+ }
337
+
338
+ /// A template instantiation's concrete template argument is only used if
339
+ /// the template definition uses the corresponding template parameter.
340
+ fn constrain_instantiation ( & self ,
341
+ used_by_this_id : & mut ItemSet ,
342
+ instantiation : & TemplateInstantiation ) {
343
+ debug ! ( " template instantiation" ) ;
344
+
345
+ let decl = self . ctx . resolve_type ( instantiation. template_definition ( ) ) ;
346
+ let args = instantiation. template_arguments ( ) ;
347
+
348
+ let params = decl. self_template_params ( self . ctx )
349
+ . unwrap_or ( vec ! [ ] ) ;
350
+
351
+ let used_by_def = self . used [ & instantiation. template_definition ( ) ]
352
+ . as_ref ( )
353
+ . unwrap ( ) ;
354
+
355
+ for ( arg, param) in args. iter ( ) . zip ( params. iter ( ) ) {
356
+ debug ! ( " instantiation's argument {:?} is used if definition's \
357
+ parameter {:?} is used",
358
+ arg,
359
+ param) ;
360
+
361
+ if used_by_def. contains ( param) {
362
+ debug ! ( " param is used by template definition" ) ;
363
+
364
+ let arg = arg. into_resolver ( )
365
+ . through_type_refs ( )
366
+ . through_type_aliases ( )
367
+ . resolve ( self . ctx ) ;
368
+ if let Some ( named) = arg. as_named ( self . ctx , & ( ) ) {
369
+ debug ! ( " arg is a type parameter, marking used" ) ;
370
+ used_by_this_id. insert ( named) ;
371
+ }
372
+ }
373
+ }
374
+ }
375
+
376
+ /// The join operation on our lattice: the set union of all of this id's
377
+ /// successors.
378
+ fn constrain_join ( & self , used_by_this_id : & mut ItemSet , item : & Item ) {
379
+ debug ! ( " other item: join with successors' usage" ) ;
380
+
381
+ item. trace ( self . ctx , & mut |sub_id, edge_kind| {
382
+ // Ignore ourselves, since union with ourself is a
383
+ // no-op. Ignore edges that aren't relevant to the
384
+ // analysis. Ignore edges to blacklisted items.
385
+ if sub_id == item. id ( ) ||
386
+ !Self :: consider_edge ( edge_kind) ||
387
+ !self . whitelisted_items . contains ( & sub_id) {
388
+ return ;
389
+ }
390
+
391
+ let used_by_sub_id = self . used [ & sub_id]
392
+ . as_ref ( )
393
+ . expect ( "Because sub_id != id, and all used template \
394
+ param sets other than id's are `Some`, \
395
+ sub_id's used template param set should be \
396
+ `Some`")
397
+ . iter ( )
398
+ . cloned ( ) ;
399
+
400
+ debug ! ( " union with {:?}'s usage: {:?}" ,
401
+ sub_id,
402
+ used_by_sub_id. clone( ) . collect:: <Vec <_>>( ) ) ;
403
+
404
+ used_by_this_id. extend ( used_by_sub_id) ;
405
+ } , & ( ) ) ;
406
+ }
310
407
}
311
408
312
409
impl < ' ctx , ' gen > MonotoneFramework for UsedTemplateParameters < ' ctx , ' gen > {
@@ -418,13 +515,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
418
515
// on other hash map entries. We *must* put it back into the hash map at
419
516
// the end of this method. This allows us to side-step HashMap's lack of
420
517
// an analog to slice::split_at_mut.
421
- let mut used_by_this_id = self . used
422
- . get_mut ( & id)
423
- . expect ( "Should have a set of used template params for every item \
424
- id")
425
- . take ( )
426
- . expect ( "Should maintain the invariant that all used template param \
427
- sets are `Some` upon entry of `constrain`") ;
518
+ let mut used_by_this_id = self . take_this_id_usage_set ( id) ;
428
519
429
520
debug ! ( "constrain {:?}" , id) ;
430
521
debug ! ( " initially, used set is {:?}" , used_by_this_id) ;
@@ -439,91 +530,19 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
439
530
debug ! ( " named type, trivially uses itself" ) ;
440
531
used_by_this_id. insert ( id) ;
441
532
}
442
-
443
- // We say that blacklisted items use all of their template
444
- // parameters. The blacklisted type is most likely implemented
445
- // explicitly by the user, since it won't be in the generated
446
- // bindings, and we don't know exactly what they'll to with template
447
- // parameters, but we can push the issue down the line to them.
448
- Some ( & TypeKind :: TemplateInstantiation ( ref inst) )
449
- if !self . whitelisted_items . contains ( & inst. template_definition ( ) ) => {
450
- debug ! ( " instantiation of blacklisted template, uses all template \
451
- arguments") ;
452
-
453
- let args = inst. template_arguments ( )
454
- . iter ( )
455
- . filter_map ( |a| a. as_named ( self . ctx , & ( ) ) ) ;
456
- used_by_this_id. extend ( args) ;
457
- }
458
-
459
- // A template instantiation's concrete template argument is
460
- // only used if the template declaration uses the
461
- // corresponding template parameter.
533
+ // Template instantiations only use their template arguments if the
534
+ // template definition uses the corresponding template parameter.
462
535
Some ( & TypeKind :: TemplateInstantiation ( ref inst) ) => {
463
- debug ! ( " template instantiation" ) ;
464
-
465
- let decl = self . ctx . resolve_type ( inst. template_definition ( ) ) ;
466
- let args = inst. template_arguments ( ) ;
467
-
468
- let params = decl. self_template_params ( self . ctx )
469
- . unwrap_or ( vec ! [ ] ) ;
470
-
471
- let used_by_def = self . used [ & inst. template_definition ( ) ]
472
- . as_ref ( )
473
- . unwrap ( ) ;
474
-
475
- for ( arg, param) in args. iter ( ) . zip ( params. iter ( ) ) {
476
- debug ! ( " instantiation's argument {:?} is used if definition's \
477
- parameter {:?} is used",
478
- arg,
479
- param) ;
480
-
481
- if used_by_def. contains ( param) {
482
- debug ! ( " param is used by template definition" ) ;
483
-
484
- let arg = arg. into_resolver ( )
485
- . through_type_refs ( )
486
- . through_type_aliases ( )
487
- . resolve ( self . ctx ) ;
488
- if let Some ( named) = arg. as_named ( self . ctx , & ( ) ) {
489
- debug ! ( " arg is a type parameter, marking used" ) ;
490
- used_by_this_id. insert ( named) ;
491
- }
492
- }
536
+ if self . whitelisted_items . contains ( & inst. template_definition ( ) ) {
537
+ self . constrain_instantiation ( & mut used_by_this_id, inst) ;
538
+ } else {
539
+ self . constrain_instantiation_of_blacklisted_template ( & mut used_by_this_id,
540
+ inst) ;
493
541
}
494
542
}
495
-
496
543
// Otherwise, add the union of each of its referent item's template
497
544
// parameter usage.
498
- _ => {
499
- debug ! ( " other item: join with successors' usage" ) ;
500
-
501
- item. trace ( self . ctx , & mut |sub_id, edge_kind| {
502
- // Ignore ourselves, since union with ourself is a
503
- // no-op. Ignore edges that aren't relevant to the
504
- // analysis. Ignore edges to blacklisted items.
505
- if sub_id == id ||
506
- !Self :: consider_edge ( edge_kind) ||
507
- !self . whitelisted_items . contains ( & sub_id) {
508
- return ;
509
- }
510
-
511
- let used_by_sub_id = self . used [ & sub_id]
512
- . as_ref ( )
513
- . expect ( "Because sub_id != id, and all used template \
514
- param sets other than id's are `Some`, \
515
- sub_id's used template param set should be \
516
- `Some`")
517
- . iter ( )
518
- . cloned ( ) ;
519
-
520
- debug ! ( " union with {:?}'s usage: {:?}" ,
521
- sub_id,
522
- used_by_sub_id. clone( ) . collect:: <Vec <_>>( ) ) ;
523
-
524
- used_by_this_id. extend ( used_by_sub_id) ;
525
- } , & ( ) ) ;
526
- }
545
+ _ => self . constrain_join ( & mut used_by_this_id, item) ,
527
546
}
528
547
529
548
debug ! ( " finally, used set is {:?}" , used_by_this_id) ;
0 commit comments