@@ -18,6 +18,7 @@ use rustc_middle::ty::query::Providers;
18
18
use rustc_middle:: ty:: TyCtxt ;
19
19
use rustc_span:: source_map;
20
20
use rustc_span:: Span ;
21
+ use smallvec:: SmallVec ;
21
22
22
23
use std:: mem;
23
24
@@ -203,6 +204,106 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
203
204
visitor. cx . parent = prev_parent;
204
205
}
205
206
207
+ fn mark_local_terminating_scopes < ' tcx > ( expr : & ' tcx hir:: Expr < ' tcx > ) -> FxHashSet < hir:: ItemLocalId > {
208
+ struct LocalAccessResolutionVisitor < ' a > {
209
+ locals : & ' a mut FxHashSet < hir:: ItemLocalId > ,
210
+ }
211
+ impl < ' a > LocalAccessResolutionVisitor < ' a > {
212
+ fn probe < ' b > ( & mut self , expr : & ' b Expr < ' b > ) {
213
+ if self . locals . contains ( & expr. hir_id . local_id ) {
214
+ return ;
215
+ }
216
+ let mut nested_expr = expr;
217
+ let mut ops = SmallVec :: < [ _ ; 4 ] > :: new ( ) ;
218
+ enum OpTy {
219
+ Ref ,
220
+ Deref ,
221
+ Project ,
222
+ Local ,
223
+ }
224
+ loop {
225
+ match nested_expr. kind {
226
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
227
+ _,
228
+ hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ,
229
+ ) ) => {
230
+ ops. push ( ( nested_expr, OpTy :: Local ) ) ;
231
+ break ;
232
+ }
233
+ hir:: ExprKind :: AddrOf ( _, _, subexpr) => {
234
+ ops. push ( ( nested_expr, OpTy :: Ref ) ) ;
235
+ nested_expr = subexpr;
236
+ }
237
+ hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , subexpr) => {
238
+ ops. push ( ( nested_expr, OpTy :: Deref ) ) ;
239
+ nested_expr = subexpr;
240
+ }
241
+ hir:: ExprKind :: Field ( subexpr, _) => {
242
+ ops. push ( ( nested_expr, OpTy :: Project ) ) ;
243
+ nested_expr = subexpr;
244
+ }
245
+ hir:: ExprKind :: Index ( subexpr, idxexpr) => {
246
+ ops. push ( ( nested_expr, OpTy :: Project ) ) ;
247
+ nested_expr = subexpr;
248
+ intravisit:: walk_expr ( self , idxexpr) ;
249
+ }
250
+ _ => {
251
+ drop ( ops) ;
252
+ intravisit:: walk_expr ( self , expr) ;
253
+ return ;
254
+ }
255
+ }
256
+ }
257
+ let mut ref_level = SmallVec :: < [ _ ; 4 ] > :: new ( ) ;
258
+ let mut ops_iter = ops. into_iter ( ) . rev ( ) ;
259
+ ops_iter. next ( ) . unwrap ( ) ;
260
+ for ( expr, op) in ops_iter {
261
+ match op {
262
+ OpTy :: Ref => {
263
+ ref_level. push ( expr) ;
264
+ }
265
+ OpTy :: Deref => {
266
+ if let Some ( ref_expr) = ref_level. pop ( ) {
267
+ self . locals . insert ( ref_expr. hir_id . local_id ) ;
268
+ }
269
+ }
270
+ OpTy :: Project => {
271
+ ref_level. clear ( ) ;
272
+ }
273
+ OpTy :: Local => {
274
+ panic ! ( "unexpected encounter of Local" )
275
+ }
276
+ }
277
+ }
278
+ self . locals . insert ( expr. hir_id . local_id ) ;
279
+ }
280
+ }
281
+ impl < ' a , ' b > Visitor < ' a > for LocalAccessResolutionVisitor < ' b > {
282
+ type Map = intravisit:: ErasedMap < ' a > ;
283
+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
284
+ NestedVisitorMap :: None
285
+ }
286
+ fn visit_expr ( & mut self , expr : & ' a Expr < ' a > ) {
287
+ match expr. kind {
288
+ hir:: ExprKind :: AddrOf ( ..)
289
+ | hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , _)
290
+ | hir:: ExprKind :: Field ( ..)
291
+ | hir:: ExprKind :: Index ( ..)
292
+ | hir:: ExprKind :: Path ( ..) => self . probe ( expr) ,
293
+ hir:: ExprKind :: Block ( ..)
294
+ | hir:: ExprKind :: Closure ( ..)
295
+ | hir:: ExprKind :: ConstBlock ( ..) => { }
296
+ _ => intravisit:: walk_expr ( self , expr) ,
297
+ }
298
+ }
299
+ }
300
+ let mut locals = Default :: default ( ) ;
301
+ let mut resolution_visitor = LocalAccessResolutionVisitor { locals : & mut locals } ;
302
+ resolution_visitor. visit_expr ( expr) ;
303
+ // visitor.terminating_scopes.extend(locals.iter().copied());
304
+ locals
305
+ }
306
+
206
307
fn resolve_expr < ' tcx > ( visitor : & mut RegionResolutionVisitor < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
207
308
debug ! ( "resolve_expr - pre-increment {} expr = {:?}" , visitor. expr_and_pat_count, expr) ;
208
309
@@ -396,7 +497,15 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
396
497
let expr_cx = visitor. cx ;
397
498
visitor. enter_scope ( Scope { id : then. hir_id . local_id , data : ScopeData :: IfThen } ) ;
398
499
visitor. cx . var_parent = visitor. cx . parent ;
399
- visitor. visit_expr ( cond) ;
500
+ {
501
+ visitor. visit_expr ( cond) ;
502
+ let lifetime = Scope { id : cond. hir_id . local_id , data : ScopeData :: Node } ;
503
+ for local in mark_local_terminating_scopes ( cond) {
504
+ if local != cond. hir_id . local_id {
505
+ visitor. scope_tree . record_local_access_scope ( local, lifetime) ;
506
+ }
507
+ }
508
+ }
400
509
visitor. visit_expr ( then) ;
401
510
visitor. cx = expr_cx;
402
511
visitor. visit_expr ( otherwise) ;
@@ -406,11 +515,39 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
406
515
let expr_cx = visitor. cx ;
407
516
visitor. enter_scope ( Scope { id : then. hir_id . local_id , data : ScopeData :: IfThen } ) ;
408
517
visitor. cx . var_parent = visitor. cx . parent ;
409
- visitor. visit_expr ( cond) ;
518
+ {
519
+ visitor. visit_expr ( cond) ;
520
+ let lifetime = Scope { id : cond. hir_id . local_id , data : ScopeData :: Node } ;
521
+ for local in mark_local_terminating_scopes ( cond) {
522
+ if local != cond. hir_id . local_id {
523
+ visitor. scope_tree . record_local_access_scope ( local, lifetime) ;
524
+ }
525
+ }
526
+ }
410
527
visitor. visit_expr ( then) ;
411
528
visitor. cx = expr_cx;
412
529
}
413
530
531
+ hir:: ExprKind :: Match ( subexpr, arms, _) => {
532
+ visitor. visit_expr ( subexpr) ;
533
+ let lifetime = Scope { id : subexpr. hir_id . local_id , data : ScopeData :: Node } ;
534
+ for local in mark_local_terminating_scopes ( subexpr) {
535
+ if local != subexpr. hir_id . local_id {
536
+ visitor. scope_tree . record_local_access_scope ( local, lifetime) ;
537
+ }
538
+ }
539
+ walk_list ! ( visitor, visit_arm, arms) ;
540
+ }
541
+
542
+ hir:: ExprKind :: Index ( subexpr, idxexpr) => {
543
+ visitor. visit_expr ( subexpr) ;
544
+ visitor. visit_expr ( idxexpr) ;
545
+ visitor. scope_tree . record_eager_scope (
546
+ idxexpr. hir_id . local_id ,
547
+ Scope { id : expr. hir_id . local_id , data : ScopeData :: Node } ,
548
+ ) ;
549
+ }
550
+
414
551
_ => intravisit:: walk_expr ( visitor, expr) ,
415
552
}
416
553
@@ -683,10 +820,17 @@ fn resolve_local<'tcx>(
683
820
visitor. scope_tree . record_rvalue_scope ( expr. hir_id . local_id , blk_scope) ;
684
821
685
822
match expr. kind {
686
- hir:: ExprKind :: AddrOf ( _, _, ref subexpr)
687
- | hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , ref subexpr)
688
- | hir:: ExprKind :: Field ( ref subexpr, _)
689
- | hir:: ExprKind :: Index ( ref subexpr, _) => {
823
+ hir:: ExprKind :: AddrOf ( _, _, subexpr)
824
+ | hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , subexpr)
825
+ | hir:: ExprKind :: Field ( subexpr, _)
826
+ | hir:: ExprKind :: Index ( subexpr, _) => {
827
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
828
+ _,
829
+ hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ,
830
+ ) ) = & subexpr. kind
831
+ {
832
+ return ;
833
+ }
690
834
expr = & subexpr;
691
835
}
692
836
_ => {
0 commit comments