@@ -19,6 +19,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
1919use ty:: ParameterEnvironment ;
2020use ty:: fold:: TypeVisitor ;
2121use ty:: layout:: { Layout , LayoutError } ;
22+ use ty:: subst:: { Subst , Kind } ;
2223use ty:: TypeVariants :: * ;
2324use util:: common:: ErrorReported ;
2425use util:: nodemap:: { FxHashMap , FxHashSet } ;
@@ -385,6 +386,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
385386 None => return None ,
386387 } ;
387388
389+ Some ( ty:: Destructor { did : dtor_did } )
390+ }
391+
392+ /// Return the set of types that are required to be alive in
393+ /// order to run the destructor of `def` (see RFCs 769 and
394+ /// 1238).
395+ ///
396+ /// Note that this returns only the constraints for the
397+ /// destructor of `def` itself. For the destructors of the
398+ /// contents, you need `adt_dtorck_constraint`.
399+ pub fn destructor_constraints ( self , def : & ' tcx ty:: AdtDef )
400+ -> Vec < ty:: subst:: Kind < ' tcx > >
401+ {
402+ let dtor = match def. destructor ( self ) {
403+ None => {
404+ debug ! ( "destructor_constraints({:?}) - no dtor" , def. did) ;
405+ return vec ! [ ]
406+ }
407+ Some ( dtor) => dtor. did
408+ } ;
409+
388410 // RFC 1238: if the destructor method is tagged with the
389411 // attribute `unsafe_destructor_blind_to_params`, then the
390412 // compiler is being instructed to *assume* that the
@@ -394,11 +416,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
394416 // Such access can be in plain sight (e.g. dereferencing
395417 // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
396418 // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
397- let is_dtorck = !self . has_attr ( dtor_did, "unsafe_destructor_blind_to_params" ) ;
398- Some ( ty:: Destructor { did : dtor_did, is_dtorck : is_dtorck } )
419+ if self . has_attr ( dtor, "unsafe_destructor_blind_to_params" ) {
420+ debug ! ( "destructor_constraint({:?}) - blind" , def. did) ;
421+ return vec ! [ ] ;
422+ }
423+
424+ let impl_def_id = self . associated_item ( dtor) . container . id ( ) ;
425+ let impl_generics = self . item_generics ( impl_def_id) ;
426+
427+ // We have a destructor - all the parameters that are not
428+ // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute)
429+ // must be live.
430+
431+ // We need to return the list of parameters from the ADTs
432+ // generics/substs that correspond to impure parameters on the
433+ // impl's generics. This is a bit ugly, but conceptually simple:
434+ //
435+ // Suppose our ADT looks like the following
436+ //
437+ // struct S<X, Y, Z>(X, Y, Z);
438+ //
439+ // and the impl is
440+ //
441+ // impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0>
442+ //
443+ // We want to return the parameters (X, Y). For that, we match
444+ // up the item-substs <X, Y, Z> with the substs on the impl ADT,
445+ // <P1, P2, P0>, and then look up which of the impl substs refer to
446+ // parameters marked as pure.
447+
448+ let impl_substs = match self . item_type ( impl_def_id) . sty {
449+ ty:: TyAdt ( def_, substs) if def_ == def => substs,
450+ _ => bug ! ( )
451+ } ;
452+
453+ let item_substs = match self . item_type ( def. did ) . sty {
454+ ty:: TyAdt ( def_, substs) if def_ == def => substs,
455+ _ => bug ! ( )
456+ } ;
457+
458+ let result = item_substs. iter ( ) . zip ( impl_substs. iter ( ) )
459+ . filter ( |& ( _, & k) | {
460+ if let Some ( & ty:: Region :: ReEarlyBound ( ref ebr) ) = k. as_region ( ) {
461+ !impl_generics. region_param ( ebr) . pure_wrt_drop
462+ } else if let Some ( & ty:: TyS {
463+ sty : ty:: TypeVariants :: TyParam ( ref pt) , ..
464+ } ) = k. as_type ( ) {
465+ !impl_generics. type_param ( pt) . pure_wrt_drop
466+ } else {
467+ // not a type or region param - this should be reported
468+ // as an error.
469+ false
470+ }
471+ } ) . map ( |( & item_param, _) | item_param) . collect ( ) ;
472+ debug ! ( "destructor_constraint({:?}) = {:?}" , def. did, result) ;
473+ result
474+ }
475+
476+ /// Return a set of constraints that needs to be satisfied in
477+ /// order for `ty` to be valid for destruction.
478+ pub fn dtorck_constraint_for_ty ( self ,
479+ span : Span ,
480+ for_ty : Ty < ' tcx > ,
481+ depth : usize ,
482+ ty : Ty < ' tcx > )
483+ -> Result < ty:: DtorckConstraint < ' tcx > , ErrorReported >
484+ {
485+ debug ! ( "dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})" ,
486+ span, for_ty, depth, ty) ;
487+
488+ if depth >= self . sess . recursion_limit . get ( ) {
489+ let mut err = struct_span_err ! (
490+ self . sess, span, E0320 ,
491+ "overflow while adding drop-check rules for {}" , for_ty) ;
492+ err. note ( & format ! ( "overflowed on {}" , ty) ) ;
493+ err. emit ( ) ;
494+ return Err ( ErrorReported ) ;
495+ }
496+
497+ let result = match ty. sty {
498+ ty:: TyBool | ty:: TyChar | ty:: TyInt ( _) | ty:: TyUint ( _) |
499+ ty:: TyFloat ( _) | ty:: TyStr | ty:: TyNever |
500+ ty:: TyRawPtr ( ..) | ty:: TyRef ( ..) | ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) => {
501+ // these types never have a destructor
502+ Ok ( ty:: DtorckConstraint :: empty ( ) )
503+ }
504+
505+ ty:: TyArray ( ety, _) | ty:: TySlice ( ety) => {
506+ // single-element containers, behave like their element
507+ self . dtorck_constraint_for_ty ( span, for_ty, depth+1 , ety)
508+ }
509+
510+ ty:: TyTuple ( tys, _) => {
511+ tys. iter ( ) . map ( |ty| {
512+ self . dtorck_constraint_for_ty ( span, for_ty, depth+1 , ty)
513+ } ) . collect ( )
514+ }
515+
516+ ty:: TyClosure ( def_id, substs) => {
517+ substs. upvar_tys ( def_id, self ) . map ( |ty| {
518+ self . dtorck_constraint_for_ty ( span, for_ty, depth+1 , ty)
519+ } ) . collect ( )
520+ }
521+
522+ ty:: TyAdt ( def, substs) => {
523+ let ty:: DtorckConstraint {
524+ dtorck_types, outlives
525+ } = ty:: queries:: adt_dtorck_constraint:: get ( self , span, def. did ) ;
526+ Ok ( ty:: DtorckConstraint {
527+ // FIXME: we can try to recursively `dtorck_constraint_on_ty`
528+ // there, but that needs some way to handle cycles.
529+ dtorck_types : dtorck_types. subst ( self , substs) ,
530+ outlives : outlives. subst ( self , substs)
531+ } )
532+ }
533+
534+ // Objects must be alive in order for their destructor
535+ // to be called.
536+ ty:: TyDynamic ( ..) => Ok ( ty:: DtorckConstraint {
537+ outlives : vec ! [ Kind :: from( ty) ] ,
538+ dtorck_types : vec ! [ ] ,
539+ } ) ,
540+
541+ // Types that can't be resolved. Pass them forward.
542+ ty:: TyProjection ( ..) | ty:: TyAnon ( ..) | ty:: TyParam ( ..) => {
543+ Ok ( ty:: DtorckConstraint {
544+ outlives : vec ! [ ] ,
545+ dtorck_types : vec ! [ ty] ,
546+ } )
547+ }
548+
549+ ty:: TyInfer ( ..) | ty:: TyError => {
550+ self . sess . delay_span_bug ( span, "unresolved type in dtorck" ) ;
551+ Err ( ErrorReported )
552+ }
553+ } ;
554+
555+ debug ! ( "dtorck_constraint_for_ty({:?}) = {:?}" , ty, result) ;
556+ result
399557 }
400558
401- pub fn closure_base_def_id ( & self , def_id : DefId ) -> DefId {
559+ pub fn closure_base_def_id ( self , def_id : DefId ) -> DefId {
402560 let mut def_id = def_id;
403561 while self . def_key ( def_id) . disambiguated_data . data == DefPathData :: ClosureExpr {
404562 def_id = self . parent_def_id ( def_id) . unwrap_or_else ( || {
0 commit comments