8
8
9
9
use std:: mem;
10
10
11
+ use rustc_data_structures:: fx:: FxHashMap ;
11
12
use rustc_hir as hir;
12
13
use rustc_hir:: def_id:: DefId ;
13
14
use rustc_hir:: intravisit:: { self , Visitor } ;
@@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> {
44
45
scope_tree : ScopeTree ,
45
46
46
47
cx : Context ,
48
+
49
+ extended_super_lets : FxHashMap < hir:: ItemLocalId , Option < Scope > > ,
47
50
}
48
51
49
52
/// 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
214
217
let stmt_id = stmt. hir_id . local_id ;
215
218
debug ! ( "resolve_stmt(stmt.id={:?})" , stmt_id) ;
216
219
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.
222
235
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 ) ;
225
238
226
- intravisit:: walk_stmt ( visitor, stmt) ;
239
+ intravisit:: walk_stmt ( visitor, stmt) ;
227
240
228
- visitor. cx . parent = prev_parent;
241
+ visitor. cx . parent = prev_parent;
242
+ }
229
243
}
230
244
231
245
fn resolve_expr < ' tcx > (
@@ -485,10 +499,9 @@ fn resolve_local<'tcx>(
485
499
visitor : & mut ScopeResolutionVisitor < ' tcx > ,
486
500
pat : Option < & ' tcx hir:: Pat < ' tcx > > ,
487
501
init : Option < & ' tcx hir:: Expr < ' tcx > > ,
502
+ super_let : bool ,
488
503
) {
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) ;
492
505
493
506
// As an exception to the normal rules governing temporary
494
507
// lifetimes, initializers in a let have a temporary lifetime
@@ -546,14 +559,50 @@ fn resolve_local<'tcx>(
546
559
// A, but the inner rvalues `a()` and `b()` have an extended lifetime
547
560
// due to rule C.
548
561
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
+
549
595
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 ) ;
551
597
552
598
if let Some ( pat) = pat {
553
599
if is_binding_pat ( pat) {
554
600
visitor. scope_tree . record_rvalue_candidate (
555
601
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
+ } ,
557
606
) ;
558
607
}
559
608
}
@@ -565,6 +614,7 @@ fn resolve_local<'tcx>(
565
614
if let Some ( expr) = init {
566
615
visitor. visit_expr ( expr) ;
567
616
}
617
+
568
618
if let Some ( pat) = pat {
569
619
visitor. visit_pat ( pat) ;
570
620
}
@@ -642,6 +692,7 @@ fn resolve_local<'tcx>(
642
692
/// | [ ..., E&, ... ]
643
693
/// | ( ..., E&, ... )
644
694
/// | {...; E&}
695
+ /// | { super let ... = E&; ... }
645
696
/// | if _ { ...; E& } else { ...; E& }
646
697
/// | match _ { ..., _ => E&, ... }
647
698
/// | box E&
@@ -678,6 +729,13 @@ fn resolve_local<'tcx>(
678
729
if let Some ( subexpr) = block. expr {
679
730
record_rvalue_scope_if_borrow_expr ( visitor, subexpr, blk_id) ;
680
731
}
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
+ }
681
739
}
682
740
hir:: ExprKind :: If ( _, then_block, else_block) => {
683
741
record_rvalue_scope_if_borrow_expr ( visitor, then_block, blk_id) ;
@@ -803,7 +861,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
803
861
local_id : body. value . hir_id . local_id ,
804
862
data : ScopeData :: Destruction ,
805
863
} ) ;
806
- resolve_local ( this, None , Some ( body. value ) ) ;
864
+ resolve_local ( this, None , Some ( body. value ) , false ) ;
807
865
}
808
866
} )
809
867
}
@@ -821,7 +879,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
821
879
resolve_expr ( self , ex, false ) ;
822
880
}
823
881
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 ( ) ) ;
825
883
}
826
884
fn visit_inline_const ( & mut self , c : & ' tcx hir:: ConstBlock ) {
827
885
let body = self . tcx . hir_body ( c. body ) ;
@@ -850,6 +908,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
850
908
cx : Context { parent : None , var_parent : None } ,
851
909
pessimistic_yield : false ,
852
910
fixup_scopes : vec ! [ ] ,
911
+ extended_super_lets : Default :: default ( ) ,
853
912
} ;
854
913
855
914
visitor. scope_tree . root_body = Some ( body. value . hir_id ) ;
0 commit comments