@@ -223,7 +223,9 @@ pub struct RegionMaps {
223223 /// table, the appropriate cleanup scope is the innermost
224224 /// enclosing statement, conditional expression, or repeating
225225 /// 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 > > ,
227229
228230 /// Encodes the hierarchy of fn bodies. Every fn body (including
229231 /// closures) forms its own distinct region hierarchy, rooted in
@@ -358,9 +360,11 @@ impl<'tcx> RegionMaps {
358360 self . var_map . insert ( var, lifetime) ;
359361 }
360362
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 > ) {
362364 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+ }
364368 self . rvalue_scopes . insert ( var, lifetime) ;
365369 }
366370
@@ -389,7 +393,7 @@ impl<'tcx> RegionMaps {
389393 // check for a designated rvalue scope
390394 if let Some ( & s) = self . rvalue_scopes . get ( & expr_id) {
391395 debug ! ( "temporary_scope({:?}) = {:?} [custom]" , expr_id, s) ;
392- return Some ( s ) ;
396+ return s ;
393397 }
394398
395399 // else, locate the innermost terminating scope
@@ -803,16 +807,11 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
803807}
804808
805809fn 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) ;
809813
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.
813814 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) ;
816815
817816 // As an exception to the normal rules governing temporary
818817 // lifetimes, initializers in a let have a temporary lifetime
@@ -872,15 +871,22 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
872871 //
873872 // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
874873
875- if let Some ( ref expr) = local . init {
874+ if let Some ( expr) = init {
876875 record_rvalue_scope_if_borrow_expr ( visitor, & expr, blk_scope) ;
877876
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+ }
880881 }
881882 }
882883
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+ }
884890
885891 /// True if `pat` match the `P&` nonterminal:
886892 ///
@@ -954,7 +960,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
954960 fn record_rvalue_scope_if_borrow_expr < ' a , ' tcx > (
955961 visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
956962 expr : & hir:: Expr ,
957- blk_id : CodeExtent )
963+ blk_id : Option < CodeExtent > )
958964 {
959965 match expr. node {
960966 hir:: ExprAddrOf ( _, ref subexpr) => {
@@ -1004,7 +1010,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
10041010 /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
10051011 fn record_rvalue_scope < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
10061012 expr : & hir:: Expr ,
1007- blk_scope : CodeExtent ) {
1013+ blk_scope : Option < CodeExtent > ) {
10081014 let mut expr = expr;
10091015 loop {
10101016 // Note: give all the expressions matching `ET` with the
@@ -1077,12 +1083,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
10771083
10781084 let outer_cx = self . cx ;
10791085 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 ) ;
10861087
10871088 if let Some ( root_id) = self . cx . root_id {
10881089 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> {
11001101
11011102 // The body of the every fn is a root scope.
11021103 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+ }
11041128
11051129 // Restore context we had at the start.
11061130 self . cx = outer_cx;
@@ -1120,7 +1144,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11201144 resolve_expr ( self , ex) ;
11211145 }
11221146 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 ) ) ;
11241148 }
11251149}
11261150
0 commit comments