@@ -478,13 +478,13 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
478
478
}
479
479
}
480
480
481
- /// This is rather subtle. When we are casting a value to a
482
- /// instantiated trait like `a as trait<'r>`, regionck already ensures
483
- /// that any borrowed pointers that appear in the type of `a` are
484
- /// bounded by `&r` . However, it is possible that there are *type
485
- /// parameters* in the type of `a`, and those *type parameters* may
486
- /// have borrowed pointers within them. We have to guarantee that the
487
- /// regions which appear in those type parameters are not obscured.
481
+ /// This is rather subtle. When we are casting a value to a instantiated
482
+ /// trait like `a as trait<'r>`, regionck already ensures that any borrowed
483
+ /// pointers that appear in the type of `a` are bounded by `'r` (ed.: modulo
484
+ /// FIXME(#5723)) . However, it is possible that there are *type parameters*
485
+ /// in the type of `a`, and those *type parameters* may have borrowed pointers
486
+ /// within them. We have to guarantee that the regions which appear in those
487
+ /// type parameters are not obscured.
488
488
///
489
489
/// Therefore, we ensure that one of three conditions holds:
490
490
///
@@ -501,6 +501,8 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
501
501
///
502
502
/// (3) The type parameter is owned (and therefore does not contain
503
503
/// borrowed ptrs).
504
+ ///
505
+ /// FIXME(#5723)---This code should probably move into regionck.
504
506
pub fn check_cast_for_escaping_regions (
505
507
cx : Context ,
506
508
source: @expr,
@@ -509,40 +511,78 @@ pub fn check_cast_for_escaping_regions(
509
511
// Determine what type we are casting to; if it is not an trait, then no
510
512
// worries.
511
513
let target_ty = ty:: expr_ty ( cx. tcx , target) ;
512
- let target_substs = match ty:: get ( target_ty) . sty {
513
- ty:: ty_trait( _, ref substs, _) => { ( /*bad*/ copy * substs) }
514
- _ => { return ; /* not a cast to a trait */ }
515
- } ;
514
+ match ty:: get ( target_ty) . sty {
515
+ ty:: ty_trait( * ) => { }
516
+ _ => { return ; }
517
+ }
518
+
519
+ // Collect up the regions that appear in the target type. We want to
520
+ // ensure that these lifetimes are shorter than all lifetimes that are in
521
+ // the source type. See test `src/test/compile-fail/regions-trait-2.rs`
522
+ let mut target_regions = ~[ ] ;
523
+ ty:: walk_regions_and_ty (
524
+ cx. tcx ,
525
+ target_ty,
526
+ |r| {
527
+ if !r. is_bound ( ) {
528
+ target_regions. push ( r) ;
529
+ }
530
+ } ,
531
+ |_| true ) ;
516
532
517
533
// Check, based on the region associated with the trait, whether it can
518
534
// possibly escape the enclosing fn item (note that all type parameters
519
- // must have been declared on the enclosing fn item):
520
- match target_substs. self_r {
521
- Some ( ty:: re_scope( * ) ) => { return ; /* case (1) */ }
522
- None | Some ( ty:: re_static) | Some ( ty:: re_free( * ) ) => { }
523
- Some ( ty:: re_bound( * ) ) | Some ( ty:: re_infer( * ) ) => {
524
- cx. tcx . sess . span_bug (
525
- source. span ,
526
- fmt ! ( "bad region found in kind: %?" , target_substs. self_r) ) ;
527
- }
535
+ // must have been declared on the enclosing fn item).
536
+ if target_regions. any ( |r| is_re_scope ( * r) ) {
537
+ return ; /* case (1) */
528
538
}
529
539
530
540
// Assuming the trait instance can escape, then ensure that each parameter
531
- // either appears in the trait type or is owned:
541
+ // either appears in the trait type or is owned.
532
542
let target_params = ty:: param_tys_in_type ( target_ty) ;
533
543
let source_ty = ty:: expr_ty ( cx. tcx , source) ;
534
- do ty:: walk_ty ( source_ty) |ty| {
535
- match ty:: get ( ty) . sty {
536
- ty:: ty_param( source_param) => {
537
- if target_params. contains ( & source_param) {
538
- /* case (2) */
539
- } else {
540
- check_durable ( cx. tcx , ty, source. span ) ; /* case (3) */
544
+ ty:: walk_regions_and_ty (
545
+ cx. tcx ,
546
+ source_ty,
547
+
548
+ |_r| {
549
+ // FIXME(#5723) --- turn this check on once &Objects are usable
550
+ //
551
+ // if !target_regions.any(|t_r| is_subregion_of(cx, *t_r, r)) {
552
+ // cx.tcx.sess.span_err(
553
+ // source.span,
554
+ // fmt!("source contains borrowed pointer with lifetime \
555
+ // not found in the target type `%s`",
556
+ // ty_to_str(cx.tcx, target_ty)));
557
+ // note_and_explain_region(
558
+ // cx.tcx, "source data is only valid for ", r, "");
559
+ // }
560
+ } ,
561
+
562
+ |ty| {
563
+ match ty:: get ( ty) . sty {
564
+ ty:: ty_param( source_param) => {
565
+ if target_params. contains ( & source_param) {
566
+ /* case (2) */
567
+ } else {
568
+ check_durable ( cx. tcx , ty, source. span ) ; /* case (3) */
569
+ }
570
+ }
571
+ _ => { }
541
572
}
542
- }
543
- _ => { }
573
+ true
574
+ } ) ;
575
+
576
+ fn is_re_scope ( +r : ty:: Region ) -> bool {
577
+ match r {
578
+ ty:: re_scope( * ) => true ,
579
+ _ => false
544
580
}
545
581
}
582
+
583
+ fn is_subregion_of ( cx : Context , r_sub : ty:: Region , r_sup : ty:: Region ) -> bool {
584
+ cx. tcx . region_maps . is_subregion_of ( r_sub, r_sup)
585
+ }
546
586
}
547
587
548
588
/// Ensures that values placed into a ~Trait are copyable and sendable.
0 commit comments