@@ -8,11 +8,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
88use rustc_hir as hir;
99use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
1010use rustc_hir:: def_id:: DefId ;
11+ use rustc_hir:: hir_id:: HirIdSet ;
1112use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
12- use rustc_hir:: { Expr , ExprKind , Pat , PatKind } ;
13+ use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
1314use rustc_middle:: middle:: region:: { self , YieldData } ;
1415use rustc_middle:: ty:: { self , Ty } ;
1516use rustc_span:: Span ;
17+ use smallvec:: SmallVec ;
1618
1719struct InteriorVisitor < ' a , ' tcx > {
1820 fcx : & ' a FnCtxt < ' a , ' tcx > ,
@@ -21,6 +23,13 @@ struct InteriorVisitor<'a, 'tcx> {
2123 expr_count : usize ,
2224 kind : hir:: GeneratorKind ,
2325 prev_unresolved_span : Option < Span > ,
26+ /// Match arm guards have temporary borrows from the pattern bindings.
27+ /// In case there is a yield point in a guard with a reference to such bindings,
28+ /// such borrows can span across this yield point.
29+ /// As such, we need to track these borrows and record them despite of the fact
30+ /// that they may succeed the said yield point in the post-order.
31+ guard_bindings : SmallVec < [ SmallVec < [ HirId ; 4 ] > ; 1 ] > ,
32+ guard_bindings_set : HirIdSet ,
2433}
2534
2635impl < ' a , ' tcx > InteriorVisitor < ' a , ' tcx > {
@@ -30,6 +39,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
3039 scope : Option < region:: Scope > ,
3140 expr : Option < & ' tcx Expr < ' tcx > > ,
3241 source_span : Span ,
42+ guard_borrowing_from_pattern : bool ,
3343 ) {
3444 use rustc_span:: DUMMY_SP ;
3545
@@ -53,7 +63,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
5363 yield_data. expr_and_pat_count, self . expr_count, source_span
5464 ) ;
5565
56- if yield_data. expr_and_pat_count >= self . expr_count {
66+ // If it is a borrowing happening in the guard,
67+ // it needs to be recorded regardless because they
68+ // do live across this yield point.
69+ if guard_borrowing_from_pattern
70+ || yield_data. expr_and_pat_count >= self . expr_count
71+ {
5772 Some ( yield_data)
5873 } else {
5974 None
@@ -134,6 +149,8 @@ pub fn resolve_interior<'a, 'tcx>(
134149 expr_count : 0 ,
135150 kind,
136151 prev_unresolved_span : None ,
152+ guard_bindings : <_ >:: default ( ) ,
153+ guard_bindings_set : <_ >:: default ( ) ,
137154 } ;
138155 intravisit:: walk_body ( & mut visitor, body) ;
139156
@@ -210,6 +227,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
210227 NestedVisitorMap :: None
211228 }
212229
230+ fn visit_arm ( & mut self , arm : & ' tcx Arm < ' tcx > ) {
231+ let Arm { guard, pat, body, .. } = arm;
232+ self . visit_pat ( pat) ;
233+ if let Some ( ref g) = guard {
234+ self . guard_bindings . push ( <_ >:: default ( ) ) ;
235+ ArmPatCollector {
236+ guard_bindings_set : & mut self . guard_bindings_set ,
237+ guard_bindings : self
238+ . guard_bindings
239+ . last_mut ( )
240+ . expect ( "should have pushed at least one earlier" ) ,
241+ }
242+ . visit_pat ( pat) ;
243+
244+ match g {
245+ Guard :: If ( ref e) => {
246+ self . visit_expr ( e) ;
247+ }
248+ }
249+
250+ let mut scope_var_ids =
251+ self . guard_bindings . pop ( ) . expect ( "should have pushed at least one earlier" ) ;
252+ for var_id in scope_var_ids. drain ( ..) {
253+ assert ! (
254+ self . guard_bindings_set. remove( & var_id) ,
255+ "variable should be placed in scope earlier"
256+ ) ;
257+ }
258+ }
259+ self . visit_expr ( body) ;
260+ }
261+
213262 fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
214263 intravisit:: walk_pat ( self , pat) ;
215264
@@ -218,11 +267,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
218267 if let PatKind :: Binding ( ..) = pat. kind {
219268 let scope = self . region_scope_tree . var_scope ( pat. hir_id . local_id ) ;
220269 let ty = self . fcx . typeck_results . borrow ( ) . pat_ty ( pat) ;
221- self . record ( ty, Some ( scope) , None , pat. span ) ;
270+ self . record ( ty, Some ( scope) , None , pat. span , false ) ;
222271 }
223272 }
224273
225274 fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
275+ let mut guard_borrowing_from_pattern = false ;
226276 match & expr. kind {
227277 ExprKind :: Call ( callee, args) => match & callee. kind {
228278 ExprKind :: Path ( qpath) => {
@@ -249,6 +299,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
249299 }
250300 _ => intravisit:: walk_expr ( self , expr) ,
251301 } ,
302+ ExprKind :: Path ( qpath) => {
303+ intravisit:: walk_expr ( self , expr) ;
304+ let res = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, expr. hir_id ) ;
305+ match res {
306+ Res :: Local ( id) if self . guard_bindings_set . contains ( & id) => {
307+ guard_borrowing_from_pattern = true ;
308+ }
309+ _ => { }
310+ }
311+ }
252312 _ => intravisit:: walk_expr ( self , expr) ,
253313 }
254314
@@ -259,18 +319,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
259319 // If there are adjustments, then record the final type --
260320 // this is the actual value that is being produced.
261321 if let Some ( adjusted_ty) = self . fcx . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( expr) {
262- self . record ( adjusted_ty, scope, Some ( expr) , expr. span ) ;
322+ self . record ( adjusted_ty, scope, Some ( expr) , expr. span , guard_borrowing_from_pattern ) ;
263323 }
264324
265325 // Also record the unadjusted type (which is the only type if
266326 // there are no adjustments). The reason for this is that the
267327 // unadjusted value is sometimes a "temporary" that would wind
268328 // up in a MIR temporary.
269329 //
270- // As an example, consider an expression like `vec![].push()`.
330+ // As an example, consider an expression like `vec![].push(x )`.
271331 // Here, the `vec![]` would wind up MIR stored into a
272332 // temporary variable `t` which we can borrow to invoke
273- // `<Vec<_>>::push(&mut t)`.
333+ // `<Vec<_>>::push(&mut t, x )`.
274334 //
275335 // Note that an expression can have many adjustments, and we
276336 // are just ignoring those intermediate types. This is because
@@ -287,9 +347,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
287347 // The type table might not have information for this expression
288348 // if it is in a malformed scope. (#66387)
289349 if let Some ( ty) = self . fcx . typeck_results . borrow ( ) . expr_ty_opt ( expr) {
290- self . record ( ty, scope, Some ( expr) , expr. span ) ;
350+ self . record ( ty, scope, Some ( expr) , expr. span , guard_borrowing_from_pattern ) ;
291351 } else {
292352 self . fcx . tcx . sess . delay_span_bug ( expr. span , "no type for node" ) ;
293353 }
294354 }
295355}
356+
357+ struct ArmPatCollector < ' a > {
358+ guard_bindings_set : & ' a mut HirIdSet ,
359+ guard_bindings : & ' a mut SmallVec < [ HirId ; 4 ] > ,
360+ }
361+
362+ impl < ' a , ' tcx > Visitor < ' tcx > for ArmPatCollector < ' a > {
363+ type Map = intravisit:: ErasedMap < ' tcx > ;
364+
365+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
366+ NestedVisitorMap :: None
367+ }
368+
369+ fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
370+ intravisit:: walk_pat ( self , pat) ;
371+ if let PatKind :: Binding ( _, id, ..) = pat. kind {
372+ self . guard_bindings . push ( id) ;
373+ self . guard_bindings_set . insert ( id) ;
374+ }
375+ }
376+ }
0 commit comments