@@ -396,19 +396,24 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
396
396
}
397
397
} ;
398
398
399
- let opt_type_did = match typ. sty {
400
- ty:: ty_struct( struct_did, _) => Some ( struct_did) ,
401
- ty:: ty_enum( enum_did, _) => Some ( enum_did) ,
402
- _ => None ,
399
+ let dtor_kind = match typ. sty {
400
+ ty:: ty_enum( def_id, _) |
401
+ ty:: ty_struct( def_id, _) => {
402
+ match destructor_for_type. get ( & def_id) {
403
+ Some ( def_id) => DtorKind :: KnownDropMethod ( * def_id) ,
404
+ None => DtorKind :: PureRecur ,
405
+ }
406
+ }
407
+ ty:: ty_trait( ref ty_trait) => {
408
+ DtorKind :: Unknown ( ty_trait. bounds . clone ( ) )
409
+ }
410
+ _ => DtorKind :: PureRecur ,
403
411
} ;
404
412
405
- let opt_dtor =
406
- opt_type_did. and_then ( |did| destructor_for_type. get ( & did) ) ;
407
-
408
413
debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
409
- {}typ: {} scope: {:?} opt_dtor: {:?} xref: {}",
414
+ {}typ: {} scope: {:?} xref: {}",
410
415
( 0 ..depth) . map( |_| ' ' ) . collect:: <String >( ) ,
411
- typ. repr( rcx. tcx( ) ) , scope, opt_dtor , xref_depth) ;
416
+ typ. repr( rcx. tcx( ) ) , scope, xref_depth) ;
412
417
413
418
// If `typ` has a destructor, then we must ensure that all
414
419
// borrowed data reachable via `typ` must outlive the parent
@@ -439,102 +444,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
439
444
// simply skip the `type_must_outlive` call entirely (but
440
445
// resume the recursive checking of the type-substructure).
441
446
442
- let has_dtor_of_interest;
443
-
444
- if let Some ( & dtor_method_did) = opt_dtor {
445
- let impl_did = ty:: impl_of_method ( rcx. tcx ( ) , dtor_method_did)
446
- . unwrap_or_else ( || {
447
- rcx. tcx ( ) . sess . span_bug (
448
- span, "no Drop impl found for drop method" )
449
- } ) ;
450
-
451
- let dtor_typescheme = ty:: lookup_item_type ( rcx. tcx ( ) , impl_did) ;
452
- let dtor_generics = dtor_typescheme. generics ;
453
-
454
- let mut has_pred_of_interest = false ;
455
-
456
- let mut seen_items = Vec :: new ( ) ;
457
- let mut items_to_inspect = vec ! [ impl_did] ;
458
- ' items: while let Some ( item_def_id) = items_to_inspect. pop ( ) {
459
- if seen_items. contains ( & item_def_id) {
460
- continue ;
461
- }
462
-
463
- for pred in ty:: lookup_predicates ( rcx. tcx ( ) , item_def_id) . predicates {
464
- let result = match pred {
465
- ty:: Predicate :: Equate ( ..) |
466
- ty:: Predicate :: RegionOutlives ( ..) |
467
- ty:: Predicate :: TypeOutlives ( ..) |
468
- ty:: Predicate :: Projection ( ..) => {
469
- // For now, assume all these where-clauses
470
- // may give drop implementation capabilty
471
- // to access borrowed data.
472
- true
473
- }
474
-
475
- ty:: Predicate :: Trait ( ty:: Binder ( ref t_pred) ) => {
476
- let def_id = t_pred. trait_ref . def_id ;
477
- if ty:: trait_items ( rcx. tcx ( ) , def_id) . len ( ) != 0 {
478
- // If trait has items, assume it adds
479
- // capability to access borrowed data.
480
- true
481
- } else {
482
- // Trait without items is itself
483
- // uninteresting from POV of dropck.
484
- //
485
- // However, may have parent w/ items;
486
- // so schedule checking of predicates,
487
- items_to_inspect. push ( def_id) ;
488
- // and say "no capability found" for now.
489
- false
490
- }
491
- }
492
- } ;
493
-
494
- if result {
495
- has_pred_of_interest = true ;
496
- debug ! ( "typ: {} has interesting dtor due to generic preds, e.g. {}" ,
497
- typ. repr( rcx. tcx( ) ) , pred. repr( rcx. tcx( ) ) ) ;
498
- break ' items;
499
- }
500
- }
501
-
502
- seen_items. push ( item_def_id) ;
503
- }
504
-
505
- // In `impl<'a> Drop ...`, we automatically assume
506
- // `'a` is meaningful and thus represents a bound
507
- // through which we could reach borrowed data.
508
- //
509
- // FIXME (pnkfelix): In the future it would be good to
510
- // extend the language to allow the user to express,
511
- // in the impl signature, that a lifetime is not
512
- // actually used (something like `where 'a: ?Live`).
513
- let has_region_param_of_interest =
514
- dtor_generics. has_region_params ( subst:: TypeSpace ) ;
515
-
516
- has_dtor_of_interest =
517
- has_region_param_of_interest ||
518
- has_pred_of_interest;
519
-
520
- if has_dtor_of_interest {
521
- debug ! ( "typ: {} has interesting dtor, due to \
522
- region params: {} or pred: {}",
523
- typ. repr( rcx. tcx( ) ) ,
524
- has_region_param_of_interest,
525
- has_pred_of_interest) ;
526
- } else {
527
- debug ! ( "typ: {} has dtor, but it is uninteresting" ,
528
- typ. repr( rcx. tcx( ) ) ) ;
529
- }
530
-
531
- } else {
532
- debug ! ( "typ: {} has no dtor, and thus is uninteresting" ,
533
- typ. repr( rcx. tcx( ) ) ) ;
534
- has_dtor_of_interest = false ;
535
- }
536
-
537
- if has_dtor_of_interest {
447
+ if has_dtor_of_interest ( rcx. tcx ( ) , dtor_kind, typ, span) {
538
448
// If `typ` has a destructor, then we must ensure that all
539
449
// borrowed data reachable via `typ` must outlive the
540
450
// parent of `scope`. (It does not suffice for it to
@@ -620,7 +530,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
620
530
621
531
ty:: ty_rptr( ..) | ty:: ty_ptr( _) | ty:: ty_bare_fn( ..) => {
622
532
// Don't recurse, since references, pointers,
623
- // boxes, and bare functions don't own instances
533
+ // and bare functions don't own instances
624
534
// of the types appearing within them.
625
535
walker. skip_current_subtree ( ) ;
626
536
}
@@ -639,3 +549,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
639
549
640
550
return Ok ( ( ) ) ;
641
551
}
552
+
553
+ enum DtorKind < ' tcx > {
554
+ // Type has an associated drop method with this def id
555
+ KnownDropMethod ( ast:: DefId ) ,
556
+
557
+ // Type has no destructor (or its dtor is known to be pure
558
+ // with respect to lifetimes), though its *substructure*
559
+ // may carry a destructor.
560
+ PureRecur ,
561
+
562
+ // Type may have impure destructor that is unknown;
563
+ // e.g. `Box<Trait+'a>`
564
+ Unknown ( ty:: ExistentialBounds < ' tcx > ) ,
565
+ }
566
+
567
+ fn has_dtor_of_interest < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
568
+ dtor_kind : DtorKind ,
569
+ typ : ty:: Ty < ' tcx > ,
570
+ span : Span ) -> bool {
571
+ let has_dtor_of_interest: bool ;
572
+
573
+ match dtor_kind {
574
+ DtorKind :: PureRecur => {
575
+ has_dtor_of_interest = false ;
576
+ debug ! ( "typ: {} has no dtor, and thus is uninteresting" ,
577
+ typ. repr( tcx) ) ;
578
+ }
579
+ DtorKind :: Unknown ( bounds) => {
580
+ match bounds. region_bound {
581
+ ty:: ReStatic => {
582
+ debug ! ( "trait: {} has 'static bound, and thus is uninteresting" ,
583
+ typ. repr( tcx) ) ;
584
+ has_dtor_of_interest = false ;
585
+ }
586
+ ty:: ReEmpty => {
587
+ debug ! ( "trait: {} has empty region bound, and thus is uninteresting" ,
588
+ typ. repr( tcx) ) ;
589
+ has_dtor_of_interest = false ;
590
+ }
591
+ r => {
592
+ debug ! ( "trait: {} has non-static bound: {}; assumed interesting" ,
593
+ typ. repr( tcx) , r. repr( tcx) ) ;
594
+ has_dtor_of_interest = true ;
595
+ }
596
+ }
597
+ }
598
+ DtorKind :: KnownDropMethod ( dtor_method_did) => {
599
+ let impl_did = ty:: impl_of_method ( tcx, dtor_method_did)
600
+ . unwrap_or_else ( || {
601
+ tcx. sess . span_bug (
602
+ span, "no Drop impl found for drop method" )
603
+ } ) ;
604
+
605
+ let dtor_typescheme = ty:: lookup_item_type ( tcx, impl_did) ;
606
+ let dtor_generics = dtor_typescheme. generics ;
607
+
608
+ let mut has_pred_of_interest = false ;
609
+
610
+ let mut seen_items = Vec :: new ( ) ;
611
+ let mut items_to_inspect = vec ! [ impl_did] ;
612
+ ' items: while let Some ( item_def_id) = items_to_inspect. pop ( ) {
613
+ if seen_items. contains ( & item_def_id) {
614
+ continue ;
615
+ }
616
+
617
+ for pred in ty:: lookup_predicates ( tcx, item_def_id) . predicates {
618
+ let result = match pred {
619
+ ty:: Predicate :: Equate ( ..) |
620
+ ty:: Predicate :: RegionOutlives ( ..) |
621
+ ty:: Predicate :: TypeOutlives ( ..) |
622
+ ty:: Predicate :: Projection ( ..) => {
623
+ // For now, assume all these where-clauses
624
+ // may give drop implementation capabilty
625
+ // to access borrowed data.
626
+ true
627
+ }
628
+
629
+ ty:: Predicate :: Trait ( ty:: Binder ( ref t_pred) ) => {
630
+ let def_id = t_pred. trait_ref . def_id ;
631
+ if ty:: trait_items ( tcx, def_id) . len ( ) != 0 {
632
+ // If trait has items, assume it adds
633
+ // capability to access borrowed data.
634
+ true
635
+ } else {
636
+ // Trait without items is itself
637
+ // uninteresting from POV of dropck.
638
+ //
639
+ // However, may have parent w/ items;
640
+ // so schedule checking of predicates,
641
+ items_to_inspect. push ( def_id) ;
642
+ // and say "no capability found" for now.
643
+ false
644
+ }
645
+ }
646
+ } ;
647
+
648
+ if result {
649
+ has_pred_of_interest = true ;
650
+ debug ! ( "typ: {} has interesting dtor due to generic preds, e.g. {}" ,
651
+ typ. repr( tcx) , pred. repr( tcx) ) ;
652
+ break ' items;
653
+ }
654
+ }
655
+
656
+ seen_items. push ( item_def_id) ;
657
+ }
658
+
659
+ // In `impl<'a> Drop ...`, we automatically assume
660
+ // `'a` is meaningful and thus represents a bound
661
+ // through which we could reach borrowed data.
662
+ //
663
+ // FIXME (pnkfelix): In the future it would be good to
664
+ // extend the language to allow the user to express,
665
+ // in the impl signature, that a lifetime is not
666
+ // actually used (something like `where 'a: ?Live`).
667
+ let has_region_param_of_interest =
668
+ dtor_generics. has_region_params ( subst:: TypeSpace ) ;
669
+
670
+ has_dtor_of_interest =
671
+ has_region_param_of_interest ||
672
+ has_pred_of_interest;
673
+
674
+ if has_dtor_of_interest {
675
+ debug ! ( "typ: {} has interesting dtor, due to \
676
+ region params: {} or pred: {}",
677
+ typ. repr( tcx) ,
678
+ has_region_param_of_interest,
679
+ has_pred_of_interest) ;
680
+ } else {
681
+ debug ! ( "typ: {} has dtor, but it is uninteresting" ,
682
+ typ. repr( tcx) ) ;
683
+ }
684
+ }
685
+ }
686
+
687
+ return has_dtor_of_interest;
688
+ }
0 commit comments