@@ -396,19 +396,24 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
396396 }
397397 } ;
398398
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 ,
403411 } ;
404412
405- let opt_dtor =
406- opt_type_did. and_then ( |did| destructor_for_type. get ( & did) ) ;
407-
408413 debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
409- {}typ: {} scope: {:?} opt_dtor: {:?} xref: {}",
414+ {}typ: {} scope: {:?} xref: {}",
410415 ( 0 ..depth) . map( |_| ' ' ) . collect:: <String >( ) ,
411- typ. repr( rcx. tcx( ) ) , scope, opt_dtor , xref_depth) ;
416+ typ. repr( rcx. tcx( ) ) , scope, xref_depth) ;
412417
413418 // If `typ` has a destructor, then we must ensure that all
414419 // borrowed data reachable via `typ` must outlive the parent
@@ -439,90 +444,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
439444 // simply skip the `type_must_outlive` call entirely (but
440445 // resume the recursive checking of the type-substructure).
441446
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) {
526448 // If `typ` has a destructor, then we must ensure that all
527449 // borrowed data reachable via `typ` must outlive the
528450 // parent of `scope`. (It does not suffice for it to
@@ -608,7 +530,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
608530
609531 ty:: ty_rptr( ..) | ty:: ty_ptr( _) | ty:: ty_bare_fn( ..) => {
610532 // Don't recurse, since references, pointers,
611- // boxes, and bare functions don't own instances
533+ // and bare functions don't own instances
612534 // of the types appearing within them.
613535 walker. skip_current_subtree ( ) ;
614536 }
@@ -627,3 +549,128 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
627549
628550 return Ok ( ( ) ) ;
629551}
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