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