@@ -19,6 +19,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
19
19
use ty:: ParameterEnvironment ;
20
20
use ty:: fold:: TypeVisitor ;
21
21
use ty:: layout:: { Layout , LayoutError } ;
22
+ use ty:: subst:: { Subst , Kind } ;
22
23
use ty:: TypeVariants :: * ;
23
24
use util:: common:: ErrorReported ;
24
25
use util:: nodemap:: { FxHashMap , FxHashSet } ;
@@ -385,6 +386,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
385
386
None => return None ,
386
387
} ;
387
388
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
+
388
410
// RFC 1238: if the destructor method is tagged with the
389
411
// attribute `unsafe_destructor_blind_to_params`, then the
390
412
// compiler is being instructed to *assume* that the
@@ -394,11 +416,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
394
416
// Such access can be in plain sight (e.g. dereferencing
395
417
// `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
396
418
// (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
399
557
}
400
558
401
- pub fn closure_base_def_id ( & self , def_id : DefId ) -> DefId {
559
+ pub fn closure_base_def_id ( self , def_id : DefId ) -> DefId {
402
560
let mut def_id = def_id;
403
561
while self . def_key ( def_id) . disambiguated_data . data == DefPathData :: ClosureExpr {
404
562
def_id = self . parent_def_id ( def_id) . unwrap_or_else ( || {
0 commit comments