@@ -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,102 +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-
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) {
538448 // If `typ` has a destructor, then we must ensure that all
539449 // borrowed data reachable via `typ` must outlive the
540450 // parent of `scope`. (It does not suffice for it to
@@ -620,7 +530,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
620530
621531 ty:: ty_rptr( ..) | ty:: ty_ptr( _) | ty:: ty_bare_fn( ..) => {
622532 // Don't recurse, since references, pointers,
623- // boxes, and bare functions don't own instances
533+ // and bare functions don't own instances
624534 // of the types appearing within them.
625535 walker. skip_current_subtree ( ) ;
626536 }
@@ -639,3 +549,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
639549
640550 return Ok ( ( ) ) ;
641551}
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