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