88
99use std:: mem;
1010
11+ use rustc_data_structures:: fx:: FxHashMap ;
1112use rustc_hir as hir;
1213use rustc_hir:: def_id:: DefId ;
1314use rustc_hir:: intravisit:: { self , Visitor } ;
@@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> {
4445 scope_tree : ScopeTree ,
4546
4647 cx : Context ,
48+
49+ extended_super_lets : FxHashMap < hir:: ItemLocalId , Option < Scope > > ,
4750}
4851
4952/// Records the lifetime of a local variable as `cx.var_parent`
@@ -214,18 +217,29 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi
214217 let stmt_id = stmt. hir_id . local_id ;
215218 debug ! ( "resolve_stmt(stmt.id={:?})" , stmt_id) ;
216219
217- // Every statement will clean up the temporaries created during
218- // execution of that statement. Therefore each statement has an
219- // associated destruction scope that represents the scope of the
220- // statement plus its destructors, and thus the scope for which
221- // regions referenced by the destructors need to survive.
220+ if let hir:: StmtKind :: Let ( LetStmt { super_ : Some ( _) , .. } ) = stmt. kind {
221+ // `super let` statement does not start a new scope, such that
222+ //
223+ // { super let x = identity(&temp()); &x }.method();
224+ //
225+ // behaves exactly as
226+ //
227+ // (&identity(&temp()).method();
228+ intravisit:: walk_stmt ( visitor, stmt) ;
229+ } else {
230+ // Every statement will clean up the temporaries created during
231+ // execution of that statement. Therefore each statement has an
232+ // associated destruction scope that represents the scope of the
233+ // statement plus its destructors, and thus the scope for which
234+ // regions referenced by the destructors need to survive.
222235
223- let prev_parent = visitor. cx . parent ;
224- visitor. enter_node_scope_with_dtor ( stmt_id, true ) ;
236+ let prev_parent = visitor. cx . parent ;
237+ visitor. enter_node_scope_with_dtor ( stmt_id, true ) ;
225238
226- intravisit:: walk_stmt ( visitor, stmt) ;
239+ intravisit:: walk_stmt ( visitor, stmt) ;
227240
228- visitor. cx . parent = prev_parent;
241+ visitor. cx . parent = prev_parent;
242+ }
229243}
230244
231245fn resolve_expr < ' tcx > (
@@ -485,10 +499,9 @@ fn resolve_local<'tcx>(
485499 visitor : & mut ScopeResolutionVisitor < ' tcx > ,
486500 pat : Option < & ' tcx hir:: Pat < ' tcx > > ,
487501 init : Option < & ' tcx hir:: Expr < ' tcx > > ,
502+ super_let : bool ,
488503) {
489- debug ! ( "resolve_local(pat={:?}, init={:?})" , pat, init) ;
490-
491- let blk_scope = visitor. cx . var_parent ;
504+ debug ! ( "resolve_local(pat={:?}, init={:?}, super_let={:?})" , pat, init, super_let) ;
492505
493506 // As an exception to the normal rules governing temporary
494507 // lifetimes, initializers in a let have a temporary lifetime
@@ -546,14 +559,50 @@ fn resolve_local<'tcx>(
546559 // A, but the inner rvalues `a()` and `b()` have an extended lifetime
547560 // due to rule C.
548561
562+ if super_let {
563+ if let Some ( scope) = visitor. extended_super_lets . remove ( & pat. unwrap ( ) . hir_id . local_id ) {
564+ // This expression was lifetime-extended by a parent let binding. E.g.
565+ //
566+ // let a = {
567+ // super let b = temp();
568+ // &b
569+ // };
570+ //
571+ // (Which needs to behave exactly as: let a = &temp();)
572+ //
573+ // Processing of `let a` will have already decided to extend the lifetime of this
574+ // `super let` to its own var_scope. We use that scope.
575+ visitor. cx . var_parent = scope;
576+ } else {
577+ // This `super let` is not subject to lifetime extension from a parent let binding. E.g.
578+ //
579+ // identity({ super let x = temp(); &x }).method();
580+ //
581+ // (Which needs to behave exactly as: identity(&temp()).method();)
582+ //
583+ // Iterate up to the enclosing destruction scope to find the same scope that will also
584+ // be used for the result of the block itself.
585+ while let Some ( s) = visitor. cx . var_parent {
586+ let parent = visitor. scope_tree . parent_map . get ( & s) . cloned ( ) ;
587+ if let Some ( Scope { data : ScopeData :: Destruction , .. } ) = parent {
588+ break ;
589+ }
590+ visitor. cx . var_parent = parent;
591+ }
592+ }
593+ }
594+
549595 if let Some ( expr) = init {
550- record_rvalue_scope_if_borrow_expr ( visitor, expr, blk_scope ) ;
596+ record_rvalue_scope_if_borrow_expr ( visitor, expr, visitor . cx . var_parent ) ;
551597
552598 if let Some ( pat) = pat {
553599 if is_binding_pat ( pat) {
554600 visitor. scope_tree . record_rvalue_candidate (
555601 expr. hir_id ,
556- RvalueCandidate { target : expr. hir_id . local_id , lifetime : blk_scope } ,
602+ RvalueCandidate {
603+ target : expr. hir_id . local_id ,
604+ lifetime : visitor. cx . var_parent ,
605+ } ,
557606 ) ;
558607 }
559608 }
@@ -565,6 +614,7 @@ fn resolve_local<'tcx>(
565614 if let Some ( expr) = init {
566615 visitor. visit_expr ( expr) ;
567616 }
617+
568618 if let Some ( pat) = pat {
569619 visitor. visit_pat ( pat) ;
570620 }
@@ -642,6 +692,7 @@ fn resolve_local<'tcx>(
642692 /// | [ ..., E&, ... ]
643693 /// | ( ..., E&, ... )
644694 /// | {...; E&}
695+ /// | { super let ... = E&; ... }
645696 /// | if _ { ...; E& } else { ...; E& }
646697 /// | match _ { ..., _ => E&, ... }
647698 /// | box E&
@@ -678,6 +729,13 @@ fn resolve_local<'tcx>(
678729 if let Some ( subexpr) = block. expr {
679730 record_rvalue_scope_if_borrow_expr ( visitor, subexpr, blk_id) ;
680731 }
732+ for stmt in block. stmts {
733+ if let hir:: StmtKind :: Let ( local) = stmt. kind
734+ && let Some ( _) = local. super_
735+ {
736+ visitor. extended_super_lets . insert ( local. pat . hir_id . local_id , blk_id) ;
737+ }
738+ }
681739 }
682740 hir:: ExprKind :: If ( _, then_block, else_block) => {
683741 record_rvalue_scope_if_borrow_expr ( visitor, then_block, blk_id) ;
@@ -803,7 +861,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
803861 local_id : body. value . hir_id . local_id ,
804862 data : ScopeData :: Destruction ,
805863 } ) ;
806- resolve_local ( this, None , Some ( body. value ) ) ;
864+ resolve_local ( this, None , Some ( body. value ) , false ) ;
807865 }
808866 } )
809867 }
@@ -821,7 +879,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
821879 resolve_expr ( self , ex, false ) ;
822880 }
823881 fn visit_local ( & mut self , l : & ' tcx LetStmt < ' tcx > ) {
824- resolve_local ( self , Some ( l. pat ) , l. init )
882+ resolve_local ( self , Some ( l. pat ) , l. init , l . super_ . is_some ( ) ) ;
825883 }
826884 fn visit_inline_const ( & mut self , c : & ' tcx hir:: ConstBlock ) {
827885 let body = self . tcx . hir_body ( c. body ) ;
@@ -850,6 +908,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
850908 cx : Context { parent : None , var_parent : None } ,
851909 pessimistic_yield : false ,
852910 fixup_scopes : vec ! [ ] ,
911+ extended_super_lets : Default :: default ( ) ,
853912 } ;
854913
855914 visitor. scope_tree . root_body = Some ( body. value . hir_id ) ;
0 commit comments