@@ -14,7 +14,6 @@ use rustc_hir::def_id::DefId;
1414use rustc_hir:: intravisit:: { self , Visitor } ;
1515use rustc_hir:: { Arm , Block , Expr , LetStmt , Pat , PatKind , Stmt } ;
1616use rustc_index:: Idx ;
17- use rustc_middle:: bug;
1817use rustc_middle:: middle:: region:: * ;
1918use rustc_middle:: thir:: TempLifetime ;
2019use rustc_middle:: ty:: TyCtxt ;
@@ -30,8 +29,9 @@ struct Context {
3029 /// Region parent of expressions, etc.
3130 parent : Option < Scope > ,
3231
33- /// Scope of lifetime-extended temporaries.
34- extended_parent : ExtendedScope ,
32+ /// Scope of lifetime-extended temporaries. If `None`, extendable expressions have their usual
33+ /// temporary scopes. This helps minimize insertions to the [`ScopeTree`]'s `rvalue_scopes` map.
34+ extended_parent : Option < ExtendedScope > ,
3535}
3636
3737/// Determines the scopes of subexpressions' temporaries.
@@ -56,9 +56,6 @@ enum ExtendedScope {
5656 /// Extendable temporaries will be dropped in the temporary scope enclosing the given scope.
5757 /// This is a separate variant to minimize calls to [`ScopeTree::default_temporary_scope`].
5858 ThroughExpression ( Scope ) ,
59- /// The outermost extended scope is set when visiting a body. To make sure we don't forget to do
60- /// so, this dummy variant is used when creating the [`ScopeResolutionVisitor`].
61- Unset ,
6259}
6360
6461impl ExtendedScope {
@@ -72,7 +69,6 @@ impl ExtendedScope {
7269 scope_tree. default_temporary_scope ( non_extending_parent) ;
7370 TempLifetime { temp_lifetime : Some ( temp_scope) , backwards_incompatible }
7471 }
75- ExtendedScope :: Unset => bug ! ( "extended parent scope not set" ) ,
7672 }
7773 }
7874}
@@ -204,6 +200,14 @@ fn resolve_block<'tcx>(
204200 . scope_tree
205201 . backwards_incompatible_scope
206202 . insert ( local_id, Scope { local_id, data : ScopeData :: Node } ) ;
203+
204+ // To avoid false positives in `tail_expr_drop_order`, make sure extendable
205+ // temporaries are extended past the block tail even if that doesn't change their
206+ // scopes in the current edition.
207+ if visitor. cx . extended_parent . is_none ( ) {
208+ visitor. cx . extended_parent =
209+ Some ( ExtendedScope :: ThroughExpression ( visitor. cx . parent . unwrap ( ) ) ) ;
210+ }
207211 }
208212 resolve_expr ( visitor, tail_expr, NodeInfo { drop_temps, extending : true } ) ;
209213 }
@@ -320,10 +324,9 @@ fn resolve_expr<'tcx>(
320324 // | E& as ...
321325 match expr. kind {
322326 hir:: ExprKind :: AddrOf ( _, _, subexpr) => {
323- // Record an extended lifetime if we haven't already done so. This makes sure we don't
324- // overwrite the scope of e.g. `temp()` in `&*&temp()` when visiting the inner `&`.
325- if !visitor. scope_tree . has_extended_scope ( subexpr. hir_id . local_id ) {
326- let lifetime = visitor. cx . extended_parent . to_scope ( & visitor. scope_tree ) ;
327+ // Record an extended lifetime for the operand if needed.
328+ if let Some ( extended_scope) = visitor. cx . extended_parent {
329+ let lifetime = extended_scope. to_scope ( & visitor. scope_tree ) ;
327330 record_subexpr_rvalue_scopes ( & mut visitor. scope_tree , subexpr, lifetime) ;
328331 }
329332 resolve_expr ( visitor, subexpr, NodeInfo { drop_temps : false , extending : true } ) ;
@@ -589,8 +592,13 @@ fn resolve_local<'tcx>(
589592 // FIXME(super_let): This ignores backward-incompatible drop hints. Implementing BIDs for
590593 // `super let` bindings could improve `tail_expr_drop_order` with regard to `pin!`, etc.
591594
592- visitor. cx . var_parent =
593- visitor. cx . extended_parent . to_scope ( & visitor. scope_tree ) . temp_lifetime ;
595+ visitor. cx . var_parent = match visitor. cx . extended_parent {
596+ Some ( extended_parent) => extended_parent. to_scope ( & visitor. scope_tree ) . temp_lifetime ,
597+ None => visitor
598+ . cx
599+ . var_parent
600+ . map ( |block| visitor. scope_tree . default_temporary_scope ( block) . 0 ) ,
601+ } ;
594602 }
595603
596604 if let Some ( expr) = init {
@@ -610,7 +618,8 @@ fn resolve_local<'tcx>(
610618 // When visiting the initializer, extend borrows and `super let`s accessible through
611619 // extending subexpressions to live in the current variable scope (or in the case of
612620 // statics and consts, for the whole program).
613- visitor. cx . extended_parent = ExtendedScope :: ThroughDeclaration ( visitor. cx . var_parent ) ;
621+ visitor. cx . extended_parent =
622+ Some ( ExtendedScope :: ThroughDeclaration ( visitor. cx . var_parent ) ) ;
614623 }
615624
616625 // Make sure we visit the initializer first.
@@ -759,14 +768,20 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> {
759768 // account for the destruction scope representing the scope of
760769 // the destructors that run immediately after it completes.
761770 if node_info. drop_temps {
771+ // If this scope corresponds to an extending subexpression, we can extend certain
772+ // temporaries' scopes through it.
773+ if node_info. extending && self . cx . extended_parent . is_none ( ) {
774+ self . cx . extended_parent = Some ( ExtendedScope :: ThroughExpression (
775+ self . cx . parent . expect ( "extending subexpressions should have parent scopes" ) ,
776+ ) ) ;
777+ }
762778 self . enter_scope ( Scope { local_id : id, data : ScopeData :: Destruction } ) ;
763779 }
764780 self . enter_scope ( Scope { local_id : id, data : ScopeData :: Node } ) ;
765781 // If this scope corresponds to a non-extending subexpression, limit the scopes of
766782 // temporaries to the enclosing temporary scope.
767783 if !node_info. extending {
768- self . cx . extended_parent =
769- ExtendedScope :: ThroughExpression ( Scope { local_id : id, data : ScopeData :: Node } ) ;
784+ self . cx . extended_parent = None ;
770785 }
771786 }
772787
@@ -881,7 +896,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
881896 let mut visitor = ScopeResolutionVisitor {
882897 tcx,
883898 scope_tree : ScopeTree :: default ( ) ,
884- cx : Context { parent : None , var_parent : None , extended_parent : ExtendedScope :: Unset } ,
899+ cx : Context { parent : None , var_parent : None , extended_parent : None } ,
885900 } ;
886901
887902 visitor. scope_tree . root_body = Some ( body. value . hir_id ) ;
0 commit comments