@@ -257,7 +257,7 @@ pub struct UsedTemplateParameters<'ctx, 'gen>
257
257
where ' gen : ' ctx
258
258
{
259
259
ctx : & ' ctx BindgenContext < ' gen > ,
260
- used : HashMap < ItemId , ItemSet > ,
260
+ used : HashMap < ItemId , Option < ItemSet > > ,
261
261
dependencies : HashMap < ItemId , Vec < ItemId > > ,
262
262
}
263
263
@@ -315,7 +315,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
315
315
316
316
for item in ctx. whitelisted_items ( ) {
317
317
dependencies. entry ( item) . or_insert ( vec ! [ ] ) ;
318
- used. insert ( item, ItemSet :: new ( ) ) ;
318
+ used. insert ( item, Some ( ItemSet :: new ( ) ) ) ;
319
319
320
320
{
321
321
// We reverse our natural IR graph edges to find dependencies
@@ -359,33 +359,47 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
359
359
}
360
360
361
361
fn constrain ( & mut self , id : ItemId ) -> bool {
362
- let original_len = self . used [ & id] . len ( ) ;
362
+ // Invariant: all hash map entries' values are `Some` upon entering and
363
+ // exiting this method.
364
+ debug_assert ! ( self . used. values( ) . all( |v| v. is_some( ) ) ) ;
365
+
366
+ // Take the set for this id out of the hash map while we mutate it based
367
+ // on other hash map entries. We *must* put it back into the hash map at
368
+ // the end of this method. This allows us to side-step HashMap's lack of
369
+ // an analog to slice::split_at_mut.
370
+ let mut used_by_this_id = self . used . get_mut ( & id) . unwrap ( ) . take ( ) . unwrap ( ) ;
371
+
372
+ let original_len = used_by_this_id. len ( ) ;
363
373
364
- // First, add this item's self template parameter usage.
365
374
let item = self . ctx . resolve_item ( id) ;
366
375
let ty_kind = item. as_type ( ) . map ( |ty| ty. kind ( ) ) ;
367
376
match ty_kind {
377
+ // Named template type parameters trivially use themselves.
368
378
Some ( & TypeKind :: Named ) => {
369
- // This is a trivial use of the template type parameter.
370
- self . used . get_mut ( & id) . unwrap ( ) . insert ( id) ;
379
+ used_by_this_id. insert ( id) ;
371
380
}
381
+
382
+ // A template instantiation's concrete template argument is
383
+ // only used if the template declaration uses the
384
+ // corresponding template parameter.
372
385
Some ( & TypeKind :: TemplateInstantiation ( ref inst) ) => {
373
386
let decl = self . ctx . resolve_type ( inst. template_definition ( ) ) ;
374
387
let args = inst. template_arguments ( ) ;
375
388
376
- // A template instantiation's concrete template argument is
377
- // only used if the template declaration uses the
378
- // corresponding template parameter.
379
389
let params = decl. self_template_params ( self . ctx )
380
390
. unwrap_or ( vec ! [ ] ) ;
381
391
for ( arg, param) in args. iter ( ) . zip ( params. iter ( ) ) {
382
- if self . used [ & inst. template_definition ( ) ] . contains ( param) {
392
+ let used_by_definition = self . used [ & inst. template_definition ( ) ]
393
+ . as_ref ( )
394
+ . unwrap ( ) ;
395
+ if used_by_definition. contains ( param) {
383
396
if let Some ( named) = arg. as_named ( self . ctx , & ( ) ) {
384
- self . used . get_mut ( & id ) . unwrap ( ) . insert ( named) ;
397
+ used_by_this_id . insert ( named) ;
385
398
}
386
399
}
387
400
}
388
401
}
402
+
389
403
// Otherwise, add the union of each of its referent item's template
390
404
// parameter usage.
391
405
_ => {
@@ -394,20 +408,23 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
394
408
return ;
395
409
}
396
410
397
- // This clone is unfortunate because we are potentially thrashing
398
- // malloc. We could investigate replacing the ItemSet values with
399
- // Rc<RefCell<ItemSet>> to make the borrow checker happy, but it
400
- // isn't clear that the added indirection wouldn't outweigh the cost
401
- // of malloc'ing a new ItemSet here. Ideally, `HashMap` would have a
402
- // `split_entries` method analogous to `slice::split_at_mut`...
403
- let to_add = self . used [ & sub_id] . clone ( ) ;
404
- self . used . get_mut ( & id) . unwrap ( ) . extend ( to_add) ;
411
+ let used_by_sub_id = self . used [ & sub_id]
412
+ . as_ref ( )
413
+ . unwrap ( )
414
+ . iter ( )
415
+ . cloned ( ) ;
416
+ used_by_this_id. extend ( used_by_sub_id) ;
405
417
} , & ( ) ) ;
406
418
}
407
419
}
408
420
409
- let new_len = self . used [ & id ] . len ( ) ;
421
+ let new_len = used_by_this_id . len ( ) ;
410
422
assert ! ( new_len >= original_len) ;
423
+
424
+ // Put the set back in the hash map and restore our invariant.
425
+ self . used . insert ( id, Some ( used_by_this_id) ) ;
426
+ debug_assert ! ( self . used. values( ) . all( |v| v. is_some( ) ) ) ;
427
+
411
428
new_len != original_len
412
429
}
413
430
@@ -425,6 +442,9 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
425
442
impl < ' ctx , ' gen > From < UsedTemplateParameters < ' ctx , ' gen > > for HashMap < ItemId , ItemSet > {
426
443
fn from ( used_templ_params : UsedTemplateParameters < ' ctx , ' gen > ) -> Self {
427
444
used_templ_params. used
445
+ . into_iter ( )
446
+ . map ( |( k, v) | ( k, v. unwrap ( ) ) )
447
+ . collect ( )
428
448
}
429
449
}
430
450
0 commit comments