@@ -24,7 +24,7 @@ use tracing::debug;
2424#[ derive( Debug , Copy , Clone ) ]
2525struct Context {
2626 /// The scope that contains any new variables declared.
27- var_parent : Option < Scope > ,
27+ var_parent : ( Option < Scope > , ScopeCompatibility ) ,
2828
2929 /// Region parent of expressions, etc.
3030 parent : Option < Scope > ,
@@ -56,14 +56,18 @@ struct ExtendedTemporaryScope {
5656
5757/// Records the lifetime of a local variable as `cx.var_parent`
5858fn record_var_lifetime ( visitor : & mut ScopeResolutionVisitor < ' _ > , var_id : hir:: ItemLocalId ) {
59- match visitor. cx . var_parent {
59+ let ( var_parent_scope, var_parent_compat) = visitor. cx . var_parent ;
60+ match var_parent_scope {
6061 None => {
6162 // this can happen in extern fn declarations like
6263 //
6364 // extern fn isalnum(c: c_int) -> c_int
6465 }
6566 Some ( parent_scope) => visitor. scope_tree . record_var_scope ( var_id, parent_scope) ,
6667 }
68+ if let ScopeCompatibility :: FutureIncompatible { shortens_to } = var_parent_compat {
69+ visitor. scope_tree . record_future_incompatible_var_scope ( var_id, shortens_to) ;
70+ }
6771}
6872
6973fn resolve_block < ' tcx > (
@@ -101,7 +105,7 @@ fn resolve_block<'tcx>(
101105 // itself has returned.
102106
103107 visitor. enter_node_scope_with_dtor ( blk. hir_id . local_id , terminating) ;
104- visitor. cx . var_parent = visitor. cx . parent ;
108+ visitor. cx . var_parent = ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
105109
106110 {
107111 // This block should be kept approximately in sync with
@@ -120,7 +124,8 @@ fn resolve_block<'tcx>(
120124 local_id : blk. hir_id . local_id ,
121125 data : ScopeData :: Remainder ( FirstStatementIndex :: new ( i) ) ,
122126 } ) ;
123- visitor. cx . var_parent = visitor. cx . parent ;
127+ visitor. cx . var_parent =
128+ ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
124129 visitor. visit_stmt ( statement) ;
125130 // We need to back out temporarily to the last enclosing scope
126131 // for the `else` block, so that even the temporaries receiving
@@ -144,7 +149,8 @@ fn resolve_block<'tcx>(
144149 local_id : blk. hir_id . local_id ,
145150 data : ScopeData :: Remainder ( FirstStatementIndex :: new ( i) ) ,
146151 } ) ;
147- visitor. cx . var_parent = visitor. cx . parent ;
152+ visitor. cx . var_parent =
153+ ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
148154 visitor. visit_stmt ( statement)
149155 }
150156 hir:: StmtKind :: Item ( ..) => {
@@ -208,15 +214,15 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir:
208214 let prev_cx = visitor. cx ;
209215
210216 visitor. enter_node_scope_with_dtor ( arm. hir_id . local_id , true ) ;
211- visitor. cx . var_parent = visitor. cx . parent ;
217+ visitor. cx . var_parent = ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
212218
213219 resolve_pat ( visitor, arm. pat ) ;
214220 if let Some ( guard) = arm. guard {
215221 // We introduce a new scope to contain bindings and temporaries from `if let` guards, to
216222 // ensure they're dropped before the arm's pattern's bindings. This extends to the end of
217223 // the arm body and is the scope of its locals as well.
218224 visitor. enter_scope ( Scope { local_id : arm. hir_id . local_id , data : ScopeData :: MatchGuard } ) ;
219- visitor. cx . var_parent = visitor. cx . parent ;
225+ visitor. cx . var_parent = ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
220226 resolve_cond ( visitor, guard) ;
221227 }
222228 resolve_expr ( visitor, arm. body , false ) ;
@@ -373,7 +379,7 @@ fn resolve_expr<'tcx>(
373379 ScopeData :: IfThen
374380 } ;
375381 visitor. enter_scope ( Scope { local_id : then. hir_id . local_id , data } ) ;
376- visitor. cx . var_parent = visitor. cx . parent ;
382+ visitor. cx . var_parent = ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
377383 resolve_cond ( visitor, cond) ;
378384 resolve_expr ( visitor, then, true ) ;
379385 visitor. cx = expr_cx;
@@ -388,7 +394,7 @@ fn resolve_expr<'tcx>(
388394 ScopeData :: IfThen
389395 } ;
390396 visitor. enter_scope ( Scope { local_id : then. hir_id . local_id , data } ) ;
391- visitor. cx . var_parent = visitor. cx . parent ;
397+ visitor. cx . var_parent = ( visitor. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
392398 resolve_cond ( visitor, cond) ;
393399 resolve_expr ( visitor, then, true ) ;
394400 visitor. cx = expr_cx;
@@ -498,7 +504,7 @@ fn resolve_local<'tcx>(
498504 //
499505 // Processing of `let a` will have already decided to extend the lifetime of this
500506 // `super let` to its own var_scope. We use that scope.
501- visitor. cx . var_parent = scope. scope ;
507+ visitor. cx . var_parent = ( scope. scope , scope . compat ) ;
502508 // Inherit compatibility from the original `let` statement. If the original `let`
503509 // was regular, lifetime extension should apply as normal. If the original `let` was
504510 // `super`, blocks within the initializer will be affected by #145838.
@@ -512,9 +518,11 @@ fn resolve_local<'tcx>(
512518 //
513519 // Iterate up to the enclosing destruction scope to find the same scope that will also
514520 // be used for the result of the block itself.
515- if let Some ( inner_scope) = visitor. cx . var_parent {
516- ( visitor. cx . var_parent , _) =
517- visitor. scope_tree . default_temporary_scope ( inner_scope)
521+ if let ( Some ( inner_scope) , _) = visitor. cx . var_parent {
522+ // NB(@dianne): This could use the incompatibility reported by
523+ // `default_temporary_scope` to make `tail_expr_drop_order` more comprehensive.
524+ visitor. cx . var_parent =
525+ ( visitor. scope_tree . default_temporary_scope ( inner_scope) . 0 , ScopeCompatibility :: FutureCompatible ) ;
518526 }
519527 // Blocks within the initializer will be affected by #145838.
520528 ( LetKind :: Super , ScopeCompatibility :: FutureCompatible )
@@ -524,7 +532,7 @@ fn resolve_local<'tcx>(
524532
525533 if let Some ( expr) = init {
526534 let scope = ExtendedTemporaryScope {
527- scope : visitor. cx . var_parent ,
535+ scope : visitor. cx . var_parent . 0 ,
528536 let_kind : source_let_kind,
529537 compat,
530538 } ;
@@ -536,8 +544,8 @@ fn resolve_local<'tcx>(
536544 expr. hir_id ,
537545 RvalueCandidate {
538546 target : expr. hir_id . local_id ,
539- lifetime : visitor. cx . var_parent ,
540- compat : ScopeCompatibility :: FutureCompatible ,
547+ lifetime : visitor. cx . var_parent . 0 ,
548+ compat : visitor . cx . var_parent . 1 ,
541549 } ,
542550 ) ;
543551 }
@@ -818,7 +826,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
818826 self . enter_body ( body. value . hir_id , |this| {
819827 if this. tcx . hir_body_owner_kind ( owner_id) . is_fn_or_closure ( ) {
820828 // The arguments and `self` are parented to the fn.
821- this. cx . var_parent = this. cx . parent ;
829+ this. cx . var_parent = ( this. cx . parent , ScopeCompatibility :: FutureCompatible ) ;
822830 for param in body. params {
823831 this. visit_pat ( param. pat ) ;
824832 }
@@ -844,7 +852,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
844852 // would *not* let the `f()` temporary escape into an outer scope
845853 // (i.e., `'static`), which means that after `g` returns, it drops,
846854 // and all the associated destruction scope rules apply.
847- this. cx . var_parent = None ;
855+ this. cx . var_parent = ( None , ScopeCompatibility :: FutureCompatible ) ;
848856 this. enter_scope ( Scope {
849857 local_id : body. value . hir_id . local_id ,
850858 data : ScopeData :: Destruction ,
@@ -896,7 +904,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
896904 let mut visitor = ScopeResolutionVisitor {
897905 tcx,
898906 scope_tree : ScopeTree :: default ( ) ,
899- cx : Context { parent : None , var_parent : None } ,
907+ cx : Context { parent : None , var_parent : ( None , ScopeCompatibility :: FutureCompatible ) } ,
900908 extended_super_lets : Default :: default ( ) ,
901909 } ;
902910
0 commit comments