@@ -27,11 +27,66 @@ use syntax::{ast, visit};
27
27
use syntax:: ast:: { Block , Item , FnDecl , NodeId , Arm , Pat , Stmt , Expr , Local } ;
28
28
use syntax:: ast_util:: { stmt_id} ;
29
29
use syntax:: ast_map;
30
+ use syntax:: ptr:: P ;
30
31
use syntax:: visit:: { Visitor , FnKind } ;
31
32
32
33
/// CodeExtent represents a statically-describable extent that can be
33
34
/// used to bound the lifetime/region for values.
34
35
///
36
+ /// `Misc(node_id)`: Any AST node that has any extent at all has the
37
+ /// `Misc(node_id)` extent. Other variants represent special cases not
38
+ /// immediately derivable from the abstract syntax tree structure.
39
+ ///
40
+ /// `DestructionScope(node_id)` represents the extent of destructors
41
+ /// implicitly-attached to `node_id` that run immediately after the
42
+ /// expression for `node_id` itself. Not every AST node carries a
43
+ /// `DestructionScope`, but those that are `terminating_scopes` do;
44
+ /// see discussion with `RegionMaps`.
45
+ ///
46
+ /// `Remainder(BlockRemainder { block, statement_index })` represents
47
+ /// the extent of user code running immediately after the initializer
48
+ /// expression for the indexed statement, until the end of the block.
49
+ ///
50
+ /// So: the following code can be broken down into the extents beneath:
51
+ /// ```
52
+ /// let a = f().g( 'b: { let x = d(); let y = d(); x.h(y) } ) ;
53
+ /// ```
54
+ ///
55
+ /// +-+ (D12.)
56
+ /// +-+ (D11.)
57
+ /// +---------+ (R10.)
58
+ /// +-+ (D9.)
59
+ /// +----------+ (M8.)
60
+ /// +----------------------+ (R7.)
61
+ /// +-+ (D6.)
62
+ /// +----------+ (M5.)
63
+ /// +-----------------------------------+ (M4.)
64
+ /// +--------------------------------------------------+ (M3.)
65
+ /// +--+ (M2.)
66
+ /// +-----------------------------------------------------------+ (M1.)
67
+ ///
68
+ /// (M1.): Misc extent of the whole `let a = ...;` statement.
69
+ /// (M2.): Misc extent of the `f()` expression.
70
+ /// (M3.): Misc extent of the `f().g(..)` expression.
71
+ /// (M4.): Misc extent of the block labelled `'b:`.
72
+ /// (M5.): Misc extent of the `let x = d();` statement
73
+ /// (D6.): DestructionScope for temporaries created during M5.
74
+ /// (R7.): Remainder extent for block `'b:`, stmt 0 (let x = ...).
75
+ /// (M8.): Misc Extent of the `let y = d();` statement.
76
+ /// (D9.): DestructionScope for temporaries created during M8.
77
+ /// (R10.): Remainder extent for block `'b:`, stmt 1 (let y = ...).
78
+ /// (D11.): DestructionScope for temporaries and bindings from block `'b:`.
79
+ /// (D12.): DestructionScope for temporaries created during M1 (e.g. f()).
80
+ ///
81
+ /// Note that while the above picture shows the destruction scopes
82
+ /// as following their corresponding misc extents, in the internal
83
+ /// data structures of the compiler the destruction scopes are
84
+ /// represented as enclosing parents. This is sound because we use the
85
+ /// enclosing parent relationship just to ensure that referenced
86
+ /// values live long enough; phrased another way, the starting point
87
+ /// of each range is not really the important thing in the above
88
+ /// picture, but rather the ending point.
89
+ ///
35
90
/// FIXME (pnkfelix): This currently derives `PartialOrd` and `Ord` to
36
91
/// placate the same deriving in `ty::FreeRegion`, but we may want to
37
92
/// actually attach a more meaningful ordering to scopes than the one
@@ -40,7 +95,24 @@ use syntax::visit::{Visitor, FnKind};
40
95
RustcDecodable , Debug , Copy ) ]
41
96
pub enum CodeExtent {
42
97
Misc ( ast:: NodeId ) ,
43
- Remainder ( BlockRemainder ) ,
98
+ DestructionScope ( ast:: NodeId ) , // extent of destructors for temporaries of node-id
99
+ Remainder ( BlockRemainder )
100
+ }
101
+
102
+ /// extent of destructors for temporaries of node-id
103
+ #[ derive( Clone , PartialEq , PartialOrd , Eq , Ord , Hash , RustcEncodable ,
104
+ RustcDecodable , Debug , Copy ) ]
105
+ pub struct DestructionScopeData {
106
+ pub node_id : ast:: NodeId
107
+ }
108
+
109
+ impl DestructionScopeData {
110
+ pub fn new ( node_id : ast:: NodeId ) -> DestructionScopeData {
111
+ DestructionScopeData { node_id : node_id }
112
+ }
113
+ pub fn to_code_extent ( & self ) -> CodeExtent {
114
+ CodeExtent :: DestructionScope ( self . node_id )
115
+ }
44
116
}
45
117
46
118
/// Represents a subscope of `block` for a binding that is introduced
@@ -82,6 +154,7 @@ impl CodeExtent {
82
154
match * self {
83
155
CodeExtent :: Misc ( node_id) => node_id,
84
156
CodeExtent :: Remainder ( br) => br. block ,
157
+ CodeExtent :: DestructionScope ( node_id) => node_id,
85
158
}
86
159
}
87
160
@@ -95,6 +168,8 @@ impl CodeExtent {
95
168
CodeExtent :: Remainder ( br) =>
96
169
CodeExtent :: Remainder ( BlockRemainder {
97
170
block : f_id ( br. block ) , first_statement_index : br. first_statement_index } ) ,
171
+ CodeExtent :: DestructionScope ( node_id) =>
172
+ CodeExtent :: DestructionScope ( f_id ( node_id) ) ,
98
173
}
99
174
}
100
175
@@ -105,7 +180,8 @@ impl CodeExtent {
105
180
match ast_map. find ( self . node_id ( ) ) {
106
181
Some ( ast_map:: NodeBlock ( ref blk) ) => {
107
182
match * self {
108
- CodeExtent :: Misc ( _) => Some ( blk. span ) ,
183
+ CodeExtent :: Misc ( _) |
184
+ CodeExtent :: DestructionScope ( _) => Some ( blk. span ) ,
109
185
110
186
CodeExtent :: Remainder ( r) => {
111
187
assert_eq ! ( r. block, blk. id) ;
@@ -455,7 +531,7 @@ impl RegionMaps {
455
531
}
456
532
457
533
( ty:: ReScope ( sub_scope) , ty:: ReFree ( ref fr) ) => {
458
- self . is_subscope_of ( sub_scope, fr. scope )
534
+ self . is_subscope_of ( sub_scope, fr. scope . to_code_extent ( ) )
459
535
}
460
536
461
537
( ty:: ReFree ( sub_fr) , ty:: ReFree ( super_fr) ) => {
@@ -567,7 +643,18 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
567
643
let prev_cx = visitor. cx ;
568
644
569
645
let blk_scope = CodeExtent :: Misc ( blk. id ) ;
570
- record_superlifetime ( visitor, blk_scope, blk. span ) ;
646
+ // If block was previously marked as a terminating scope during
647
+ // the recursive visit of its parent node in the AST, then we need
648
+ // to account for the destruction scope representing the extent of
649
+ // the destructors that run immediately after the the block itself
650
+ // completes.
651
+ if visitor. region_maps . terminating_scopes . borrow ( ) . contains ( & blk_scope) {
652
+ let dtor_scope = CodeExtent :: DestructionScope ( blk. id ) ;
653
+ record_superlifetime ( visitor, dtor_scope, blk. span ) ;
654
+ visitor. region_maps . record_encl_scope ( blk_scope, dtor_scope) ;
655
+ } else {
656
+ record_superlifetime ( visitor, blk_scope, blk. span ) ;
657
+ }
571
658
572
659
// We treat the tail expression in the block (if any) somewhat
573
660
// differently from the statements. The issue has to do with
@@ -675,7 +762,9 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) {
675
762
// statement plus its destructors, and thus the extent for which
676
763
// regions referenced by the destructors need to survive.
677
764
visitor. region_maps . mark_as_terminating_scope ( stmt_scope) ;
678
- record_superlifetime ( visitor, stmt_scope, stmt. span ) ;
765
+ let dtor_scope = CodeExtent :: DestructionScope ( stmt_id) ;
766
+ visitor. region_maps . record_encl_scope ( stmt_scope, dtor_scope) ;
767
+ record_superlifetime ( visitor, dtor_scope, stmt. span ) ;
679
768
680
769
let prev_parent = visitor. cx . parent ;
681
770
visitor. cx . parent = InnermostEnclosingExpr :: Some ( stmt_id) ;
@@ -687,15 +776,30 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
687
776
debug ! ( "resolve_expr(expr.id={:?})" , expr. id) ;
688
777
689
778
let expr_scope = CodeExtent :: Misc ( expr. id ) ;
690
- record_superlifetime ( visitor, expr_scope, expr. span ) ;
779
+ // If expr was previously marked as a terminating scope during the
780
+ // recursive visit of its parent node in the AST, then we need to
781
+ // account for the destruction scope representing the extent of
782
+ // the destructors that run immediately after the the expression
783
+ // itself completes.
784
+ if visitor. region_maps . terminating_scopes . borrow ( ) . contains ( & expr_scope) {
785
+ let dtor_scope = CodeExtent :: DestructionScope ( expr. id ) ;
786
+ record_superlifetime ( visitor, dtor_scope, expr. span ) ;
787
+ visitor. region_maps . record_encl_scope ( expr_scope, dtor_scope) ;
788
+ } else {
789
+ record_superlifetime ( visitor, expr_scope, expr. span ) ;
790
+ }
691
791
692
792
let prev_cx = visitor. cx ;
693
793
visitor. cx . parent = InnermostEnclosingExpr :: Some ( expr. id ) ;
694
794
695
795
{
696
796
let region_maps = & mut visitor. region_maps ;
697
- let terminating = |id| {
698
- let scope = CodeExtent :: from_node_id ( id) ;
797
+ let terminating = |e : & P < ast:: Expr > | {
798
+ let scope = CodeExtent :: from_node_id ( e. id ) ;
799
+ region_maps. mark_as_terminating_scope ( scope)
800
+ } ;
801
+ let terminating_block = |b : & P < ast:: Block > | {
802
+ let scope = CodeExtent :: from_node_id ( b. id ) ;
699
803
region_maps. mark_as_terminating_scope ( scope)
700
804
} ;
701
805
match expr. node {
@@ -707,26 +811,26 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
707
811
ast:: ExprBinary ( codemap:: Spanned { node : ast:: BiOr , .. } , _, ref r) => {
708
812
// For shortcircuiting operators, mark the RHS as a terminating
709
813
// scope since it only executes conditionally.
710
- terminating ( r. id ) ;
814
+ terminating ( r) ;
711
815
}
712
816
713
817
ast:: ExprIf ( _, ref then, Some ( ref otherwise) ) => {
714
- terminating ( then. id ) ;
715
- terminating ( otherwise. id ) ;
818
+ terminating_block ( then) ;
819
+ terminating ( otherwise) ;
716
820
}
717
821
718
822
ast:: ExprIf ( ref expr, ref then, None ) => {
719
- terminating ( expr. id ) ;
720
- terminating ( then. id ) ;
823
+ terminating ( expr) ;
824
+ terminating_block ( then) ;
721
825
}
722
826
723
827
ast:: ExprLoop ( ref body, _) => {
724
- terminating ( body. id ) ;
828
+ terminating_block ( body) ;
725
829
}
726
830
727
831
ast:: ExprWhile ( ref expr, ref body, _) => {
728
- terminating ( expr. id ) ;
729
- terminating ( body. id ) ;
832
+ terminating ( expr) ;
833
+ terminating_block ( body) ;
730
834
}
731
835
732
836
ast:: ExprMatch ( ..) => {
@@ -1021,6 +1125,9 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
1021
1125
1022
1126
let body_scope = CodeExtent :: from_node_id ( body. id ) ;
1023
1127
visitor. region_maps . mark_as_terminating_scope ( body_scope) ;
1128
+ let dtor_scope = CodeExtent :: DestructionScope ( body. id ) ;
1129
+ visitor. region_maps . record_encl_scope ( body_scope, dtor_scope) ;
1130
+ record_superlifetime ( visitor, dtor_scope, body. span ) ;
1024
1131
1025
1132
let outer_cx = visitor. cx ;
1026
1133
0 commit comments