@@ -221,7 +221,9 @@ pub struct RegionMaps {
221221 /// table, the appropriate cleanup scope is the innermost
222222 /// enclosing statement, conditional expression, or repeating
223223 /// 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 > > ,
225227
226228 /// Encodes the hierarchy of fn bodies. Every fn body (including
227229 /// closures) forms its own distinct region hierarchy, rooted in
@@ -356,9 +358,11 @@ impl<'tcx> RegionMaps {
356358 self . var_map . insert ( var, lifetime) ;
357359 }
358360
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 > ) {
360362 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+ }
362366 self . rvalue_scopes . insert ( var, lifetime) ;
363367 }
364368
@@ -387,7 +391,7 @@ impl<'tcx> RegionMaps {
387391 // check for a designated rvalue scope
388392 if let Some ( & s) = self . rvalue_scopes . get ( & expr_id) {
389393 debug ! ( "temporary_scope({:?}) = {:?} [custom]" , expr_id, s) ;
390- return Some ( s ) ;
394+ return s ;
391395 }
392396
393397 // else, locate the innermost terminating scope
@@ -801,16 +805,11 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
801805}
802806
803807fn 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) ;
807811
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.
811812 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) ;
814813
815814 // As an exception to the normal rules governing temporary
816815 // lifetimes, initializers in a let have a temporary lifetime
@@ -870,15 +869,22 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
870869 //
871870 // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
872871
873- if let Some ( ref expr) = local . init {
872+ if let Some ( expr) = init {
874873 record_rvalue_scope_if_borrow_expr ( visitor, & expr, blk_scope) ;
875874
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+ }
878879 }
879880 }
880881
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+ }
882888
883889 /// True if `pat` match the `P&` nonterminal:
884890 ///
@@ -952,7 +958,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
952958 fn record_rvalue_scope_if_borrow_expr < ' a , ' tcx > (
953959 visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
954960 expr : & hir:: Expr ,
955- blk_id : CodeExtent )
961+ blk_id : Option < CodeExtent > )
956962 {
957963 match expr. node {
958964 hir:: ExprAddrOf ( _, ref subexpr) => {
@@ -1002,7 +1008,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
10021008 /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
10031009 fn record_rvalue_scope < ' a , ' tcx > ( visitor : & mut RegionResolutionVisitor < ' a , ' tcx > ,
10041010 expr : & hir:: Expr ,
1005- blk_scope : CodeExtent ) {
1011+ blk_scope : Option < CodeExtent > ) {
10061012 let mut expr = expr;
10071013 loop {
10081014 // Note: give all the expressions matching `ET` with the
@@ -1075,12 +1081,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
10751081
10761082 let outer_cx = self . cx ;
10771083 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 ) ;
10841085
10851086 if let Some ( root_id) = self . cx . root_id {
10861087 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> {
10981099
10991100 // The body of the every fn is a root scope.
11001101 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+ }
11021126
11031127 // Restore context we had at the start.
11041128 self . cx = outer_cx;
@@ -1118,7 +1142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11181142 resolve_expr ( self , ex) ;
11191143 }
11201144 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 ) ) ;
11221146 }
11231147}
11241148
0 commit comments