@@ -221,7 +221,9 @@ pub struct RegionMaps {
221
221
/// table, the appropriate cleanup scope is the innermost
222
222
/// enclosing statement, conditional expression, or repeating
223
223
/// block (see `terminating_scopes`).
224
- rvalue_scopes : NodeMap < CodeExtent > ,
224
+ /// In constants, None is used to indicate that certain expressions
225
+ /// escape into 'static and should have no local cleanup scope.
226
+ rvalue_scopes : NodeMap < Option < CodeExtent > > ,
225
227
226
228
/// Encodes the hierarchy of fn bodies. Every fn body (including
227
229
/// closures) forms its own distinct region hierarchy, rooted in
@@ -356,9 +358,11 @@ impl<'tcx> RegionMaps {
356
358
self . var_map . insert ( var, lifetime) ;
357
359
}
358
360
359
- fn record_rvalue_scope ( & mut self , var : ast:: NodeId , lifetime : CodeExtent ) {
361
+ fn record_rvalue_scope ( & mut self , var : ast:: NodeId , lifetime : Option < CodeExtent > ) {
360
362
debug ! ( "record_rvalue_scope(sub={:?}, sup={:?})" , var, lifetime) ;
361
- assert ! ( var != lifetime. node_id( ) ) ;
363
+ if let Some ( lifetime) = lifetime {
364
+ assert ! ( var != lifetime. node_id( ) ) ;
365
+ }
362
366
self . rvalue_scopes . insert ( var, lifetime) ;
363
367
}
364
368
@@ -387,7 +391,7 @@ impl<'tcx> RegionMaps {
387
391
// check for a designated rvalue scope
388
392
if let Some ( & s) = self . rvalue_scopes . get ( & expr_id) {
389
393
debug ! ( "temporary_scope({:?}) = {:?} [custom]" , expr_id, s) ;
390
- return Some ( s ) ;
394
+ return s ;
391
395
}
392
396
393
397
// else, locate the innermost terminating scope
@@ -801,16 +805,11 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
801
805
}
802
806
803
807
fn resolve_local < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
804
- local : & ' tcx hir:: Local ) {
805
- debug ! ( "resolve_local(local.id={:?},local. init={:?})" ,
806
- local . id , local . init. is_some ( ) ) ;
808
+ pat : Option < & ' tcx hir:: Pat > ,
809
+ init : Option < & ' tcx hir :: Expr > ) {
810
+ debug ! ( "resolve_local(pat={:?}, init={:?})" , pat , init) ;
807
811
808
- // For convenience in trans, associate with the local-id the var
809
- // scope that will be used for any bindings declared in this
810
- // pattern.
811
812
let blk_scope = visitor. cx . var_parent ;
812
- let blk_scope = blk_scope. expect ( "locals must be within a block" ) ;
813
- visitor. region_maps . record_var_scope ( local. id , blk_scope) ;
814
813
815
814
// As an exception to the normal rules governing temporary
816
815
// lifetimes, initializers in a let have a temporary lifetime
@@ -870,15 +869,22 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
870
869
//
871
870
// FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
872
871
873
- if let Some ( ref expr) = local . init {
872
+ if let Some ( expr) = init {
874
873
record_rvalue_scope_if_borrow_expr ( visitor, & expr, blk_scope) ;
875
874
876
- if is_binding_pat ( & local. pat ) {
877
- record_rvalue_scope ( visitor, & expr, blk_scope) ;
875
+ if let Some ( pat) = pat {
876
+ if is_binding_pat ( pat) {
877
+ record_rvalue_scope ( visitor, & expr, blk_scope) ;
878
+ }
878
879
}
879
880
}
880
881
881
- intravisit:: walk_local ( visitor, local) ;
882
+ if let Some ( pat) = pat {
883
+ visitor. visit_pat ( pat) ;
884
+ }
885
+ if let Some ( expr) = init {
886
+ visitor. visit_expr ( expr) ;
887
+ }
882
888
883
889
/// True if `pat` match the `P&` nonterminal:
884
890
///
@@ -952,7 +958,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
952
958
fn record_rvalue_scope_if_borrow_expr < ' a , ' tcx > (
953
959
visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
954
960
expr : & hir:: Expr ,
955
- blk_id : CodeExtent )
961
+ blk_id : Option < CodeExtent > )
956
962
{
957
963
match expr. node {
958
964
hir:: ExprAddrOf ( _, ref subexpr) => {
@@ -1002,7 +1008,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
1002
1008
/// Note: ET is intended to match "rvalues or lvalues based on rvalues".
1003
1009
fn record_rvalue_scope < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
1004
1010
expr : & hir:: Expr ,
1005
- blk_scope : CodeExtent ) {
1011
+ blk_scope : Option < CodeExtent > ) {
1006
1012
let mut expr = expr;
1007
1013
loop {
1008
1014
// Note: give all the expressions matching `ET` with the
@@ -1075,12 +1081,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
1075
1081
1076
1082
let outer_cx = self . cx ;
1077
1083
let outer_ts = mem:: replace ( & mut self . terminating_scopes , NodeSet ( ) ) ;
1078
-
1079
- // Only functions have an outer terminating (drop) scope,
1080
- // while temporaries in constant initializers are 'static.
1081
- if let MirSource :: Fn ( _) = MirSource :: from_node ( self . tcx , owner_id) {
1082
- self . terminating_scopes . insert ( body_id. node_id ) ;
1083
- }
1084
+ self . terminating_scopes . insert ( body_id. node_id ) ;
1084
1085
1085
1086
if let Some ( root_id) = self . cx . root_id {
1086
1087
self . region_maps . record_fn_parent ( body_id. node_id , root_id) ;
@@ -1098,7 +1099,30 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
1098
1099
1099
1100
// The body of the every fn is a root scope.
1100
1101
self . cx . parent = self . cx . var_parent ;
1101
- self . visit_expr ( & body. value ) ;
1102
+ if let MirSource :: Fn ( _) = MirSource :: from_node ( self . tcx , owner_id) {
1103
+ self . visit_expr ( & body. value ) ;
1104
+ } else {
1105
+ // Only functions have an outer terminating (drop) scope, while
1106
+ // temporaries in constant initializers may be 'static, but only
1107
+ // according to rvalue lifetime semantics, using the same
1108
+ // syntactical rules used for let initializers.
1109
+ //
1110
+ // E.g. in `let x = &f();`, the temporary holding the result from
1111
+ // the `f()` call lives for the entirety of the surrounding block.
1112
+ //
1113
+ // Similarly, `const X: ... = &f();` would have the result of `f()`
1114
+ // live for `'static`, implying (if Drop restrictions on constants
1115
+ // ever get lifted) that the value *could* have a destructor, but
1116
+ // it'd get leaked instead of the destructor running during the
1117
+ // evaluation of `X` (if at all allowed by CTFE).
1118
+ //
1119
+ // However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
1120
+ // would *not* let the `f()` temporary escape into an outer scope
1121
+ // (i.e. `'static`), which means that after `g` returns, it drops,
1122
+ // and all the associated destruction scope rules apply.
1123
+ self . cx . var_parent = None ;
1124
+ resolve_local ( self , None , Some ( & body. value ) ) ;
1125
+ }
1102
1126
1103
1127
// Restore context we had at the start.
1104
1128
self . cx = outer_cx;
@@ -1118,7 +1142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
1118
1142
resolve_expr ( self , ex) ;
1119
1143
}
1120
1144
fn visit_local ( & mut self , l : & ' tcx Local ) {
1121
- resolve_local ( self , l ) ;
1145
+ resolve_local ( self , Some ( & l . pat ) , l . init . as_ref ( ) . map ( |e| & * * e ) ) ;
1122
1146
}
1123
1147
}
1124
1148
0 commit comments