@@ -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,90 +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
- let dtor_predicates = ty:: lookup_predicates ( rcx. tcx ( ) , impl_did) ;
454
-
455
- let has_pred_of_interest = dtor_predicates. predicates . iter ( ) . any ( |pred| {
456
- // In `impl<T> Drop where ...`, we automatically
457
- // assume some predicate will be meaningful and thus
458
- // represents a type through which we could reach
459
- // borrowed data. However, there can be implicit
460
- // predicates (namely for Sized), and so we still need
461
- // to walk through and filter out those cases.
462
-
463
- let result = match * pred {
464
- ty:: Predicate :: Trait ( ty:: Binder ( ref t_pred) ) => {
465
- let def_id = t_pred. trait_ref . def_id ;
466
- match rcx. tcx ( ) . lang_items . to_builtin_kind ( def_id) {
467
- // Issue 24895: deliberately do not include `BoundCopy` here.
468
- Some ( ty:: BoundSend ) |
469
- Some ( ty:: BoundSized ) |
470
- Some ( ty:: BoundSync ) => false ,
471
- _ => true ,
472
- }
473
- }
474
- ty:: Predicate :: Equate ( ..) |
475
- ty:: Predicate :: RegionOutlives ( ..) |
476
- ty:: Predicate :: TypeOutlives ( ..) |
477
- ty:: Predicate :: Projection ( ..) => {
478
- // we assume all of these where-clauses may
479
- // give the drop implementation the capabilty
480
- // to access borrowed data.
481
- true
482
- }
483
- } ;
484
-
485
- if result {
486
- debug ! ( "typ: {} has interesting dtor due to generic preds, e.g. {}" ,
487
- typ. repr( rcx. tcx( ) ) , pred. repr( rcx. tcx( ) ) ) ;
488
- }
489
-
490
- result
491
- } ) ;
492
-
493
- // In `impl<'a> Drop ...`, we automatically assume
494
- // `'a` is meaningful and thus represents a bound
495
- // through which we could reach borrowed data.
496
- //
497
- // FIXME (pnkfelix): In the future it would be good to
498
- // extend the language to allow the user to express,
499
- // in the impl signature, that a lifetime is not
500
- // actually used (something like `where 'a: ?Live`).
501
- let has_region_param_of_interest =
502
- dtor_generics. has_region_params ( subst:: TypeSpace ) ;
503
-
504
- has_dtor_of_interest =
505
- has_region_param_of_interest ||
506
- has_pred_of_interest;
507
-
508
- if has_dtor_of_interest {
509
- debug ! ( "typ: {} has interesting dtor, due to \
510
- region params: {} or pred: {}",
511
- typ. repr( rcx. tcx( ) ) ,
512
- has_region_param_of_interest,
513
- has_pred_of_interest) ;
514
- } else {
515
- debug ! ( "typ: {} has dtor, but it is uninteresting" ,
516
- typ. repr( rcx. tcx( ) ) ) ;
517
- }
518
-
519
- } else {
520
- debug ! ( "typ: {} has no dtor, and thus is uninteresting" ,
521
- typ. repr( rcx. tcx( ) ) ) ;
522
- has_dtor_of_interest = false ;
523
- }
524
-
525
- if has_dtor_of_interest {
447
+ if has_dtor_of_interest ( rcx. tcx ( ) , dtor_kind, typ, span) {
526
448
// If `typ` has a destructor, then we must ensure that all
527
449
// borrowed data reachable via `typ` must outlive the
528
450
// parent of `scope`. (It does not suffice for it to
@@ -608,7 +530,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
608
530
609
531
ty:: ty_rptr( ..) | ty:: ty_ptr( _) | ty:: ty_bare_fn( ..) => {
610
532
// Don't recurse, since references, pointers,
611
- // boxes, and bare functions don't own instances
533
+ // and bare functions don't own instances
612
534
// of the types appearing within them.
613
535
walker. skip_current_subtree ( ) ;
614
536
}
@@ -627,3 +549,128 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
627
549
628
550
return Ok ( ( ) ) ;
629
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
+ debug ! ( "typ: {} has no dtor, and thus is uninteresting" ,
576
+ typ. repr( tcx) ) ;
577
+ has_dtor_of_interest = false ;
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
+ let dtor_predicates = ty:: lookup_predicates ( tcx, impl_did) ;
608
+
609
+ let has_pred_of_interest = dtor_predicates. predicates . iter ( ) . any ( |pred| {
610
+ // In `impl<T> Drop where ...`, we automatically
611
+ // assume some predicate will be meaningful and thus
612
+ // represents a type through which we could reach
613
+ // borrowed data. However, there can be implicit
614
+ // predicates (namely for Sized), and so we still need
615
+ // to walk through and filter out those cases.
616
+
617
+ let result = match * pred {
618
+ ty:: Predicate :: Trait ( ty:: Binder ( ref t_pred) ) => {
619
+ let def_id = t_pred. trait_ref . def_id ;
620
+ match tcx. lang_items . to_builtin_kind ( def_id) {
621
+ // Issue 24895: deliberately do not include `BoundCopy` here.
622
+ Some ( ty:: BoundSend ) |
623
+ Some ( ty:: BoundSized ) |
624
+ Some ( ty:: BoundSync ) => false ,
625
+ _ => true ,
626
+ }
627
+ }
628
+ ty:: Predicate :: Equate ( ..) |
629
+ ty:: Predicate :: RegionOutlives ( ..) |
630
+ ty:: Predicate :: TypeOutlives ( ..) |
631
+ ty:: Predicate :: Projection ( ..) => {
632
+ // we assume all of these where-clauses may
633
+ // give the drop implementation the capabilty
634
+ // to access borrowed data.
635
+ true
636
+ }
637
+ } ;
638
+
639
+ if result {
640
+ debug ! ( "typ: {} has interesting dtor due to generic preds, e.g. {}" ,
641
+ typ. repr( tcx) , pred. repr( tcx) ) ;
642
+ }
643
+
644
+ result
645
+ } ) ;
646
+
647
+ // In `impl<'a> Drop ...`, we automatically assume
648
+ // `'a` is meaningful and thus represents a bound
649
+ // through which we could reach borrowed data.
650
+ //
651
+ // FIXME (pnkfelix): In the future it would be good to
652
+ // extend the language to allow the user to express,
653
+ // in the impl signature, that a lifetime is not
654
+ // actually used (something like `where 'a: ?Live`).
655
+ let has_region_param_of_interest =
656
+ dtor_generics. has_region_params ( subst:: TypeSpace ) ;
657
+
658
+ has_dtor_of_interest =
659
+ has_region_param_of_interest ||
660
+ has_pred_of_interest;
661
+
662
+ if has_dtor_of_interest {
663
+ debug ! ( "typ: {} has interesting dtor, due to \
664
+ region params: {} or pred: {}",
665
+ typ. repr( tcx) ,
666
+ has_region_param_of_interest,
667
+ has_pred_of_interest) ;
668
+ } else {
669
+ debug ! ( "typ: {} has dtor, but it is uninteresting" ,
670
+ typ. repr( tcx) ) ;
671
+ }
672
+ }
673
+ }
674
+
675
+ return has_dtor_of_interest;
676
+ }
0 commit comments