22//! normal visitor, which just walks the entire body in one shot, the
33//! `ExprUseVisitor` determines how expressions are being used.
44
5+ use std:: slice:: from_ref;
6+
57use hir:: def:: DefKind ;
8+ use hir:: Expr ;
69// Export these here so that Clippy can use them.
710pub use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , Projection } ;
811
@@ -257,91 +260,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
257260
258261 hir:: ExprKind :: Match ( ref discr, arms, _) => {
259262 let discr_place = return_if_err ! ( self . mc. cat_expr( discr) ) ;
260-
261- // Matching should not always be considered a use of the place, hence
262- // discr does not necessarily need to be borrowed.
263- // We only want to borrow discr if the pattern contain something other
264- // than wildcards.
265- let ExprUseVisitor { ref mc, body_owner : _, delegate : _ } = * self ;
266- let mut needs_to_be_read = false ;
267- for arm in arms. iter ( ) {
268- return_if_err ! ( mc. cat_pattern( discr_place. clone( ) , arm. pat, |place, pat| {
269- match & pat. kind {
270- PatKind :: Binding ( .., opt_sub_pat) => {
271- // If the opt_sub_pat is None, than the binding does not count as
272- // a wildcard for the purpose of borrowing discr.
273- if opt_sub_pat. is_none( ) {
274- needs_to_be_read = true ;
275- }
276- }
277- PatKind :: Path ( qpath) => {
278- // A `Path` pattern is just a name like `Foo`. This is either a
279- // named constant or else it refers to an ADT variant
280-
281- let res = self . mc. typeck_results. qpath_res( qpath, pat. hir_id) ;
282- match res {
283- Res :: Def ( DefKind :: Const , _)
284- | Res :: Def ( DefKind :: AssocConst , _) => {
285- // Named constants have to be equated with the value
286- // being matched, so that's a read of the value being matched.
287- //
288- // FIXME: We don't actually reads for ZSTs.
289- needs_to_be_read = true ;
290- }
291- _ => {
292- // Otherwise, this is a struct/enum variant, and so it's
293- // only a read if we need to read the discriminant.
294- needs_to_be_read |= is_multivariant_adt( place. place. ty( ) ) ;
295- }
296- }
297- }
298- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
299- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
300- // against a multivariant enum or struct. In that case, we have to read
301- // the discriminant. Otherwise this kind of pattern doesn't actually
302- // read anything (we'll get invoked for the `...`, which may indeed
303- // perform some reads).
304-
305- let place_ty = place. place. ty( ) ;
306- needs_to_be_read |= is_multivariant_adt( place_ty) ;
307- }
308- PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
309- // If the PatKind is a Lit or a Range then we want
310- // to borrow discr.
311- needs_to_be_read = true ;
312- }
313- PatKind :: Or ( _)
314- | PatKind :: Box ( _)
315- | PatKind :: Slice ( ..)
316- | PatKind :: Ref ( ..)
317- | PatKind :: Wild => {
318- // If the PatKind is Or, Box, Slice or Ref, the decision is made later
319- // as these patterns contains subpatterns
320- // If the PatKind is Wild, the decision is made based on the other patterns being
321- // examined
322- }
323- }
324- } ) ) ;
325- }
326-
327- if needs_to_be_read {
328- self . borrow_expr ( discr, ty:: ImmBorrow ) ;
329- } else {
330- let closure_def_id = match discr_place. place . base {
331- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id . to_def_id ( ) ) ,
332- _ => None ,
333- } ;
334-
335- self . delegate . fake_read (
336- & discr_place,
337- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
338- discr_place. hir_id ,
339- ) ;
340-
341- // We always want to walk the discriminant. We want to make sure, for instance,
342- // that the discriminant has been initialized.
343- self . walk_expr ( discr) ;
344- }
263+ self . maybe_read_scrutinee (
264+ discr,
265+ discr_place. clone ( ) ,
266+ arms. iter ( ) . map ( |arm| arm. pat ) ,
267+ ) ;
345268
346269 // treatment of the discriminant is handled while walking the arms.
347270 for arm in arms {
@@ -470,6 +393,97 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
470393 }
471394 }
472395
396+ fn maybe_read_scrutinee < ' t > (
397+ & mut self ,
398+ discr : & Expr < ' _ > ,
399+ discr_place : PlaceWithHirId < ' tcx > ,
400+ pats : impl Iterator < Item = & ' t hir:: Pat < ' t > > ,
401+ ) {
402+ // Matching should not always be considered a use of the place, hence
403+ // discr does not necessarily need to be borrowed.
404+ // We only want to borrow discr if the pattern contain something other
405+ // than wildcards.
406+ let ExprUseVisitor { ref mc, body_owner : _, delegate : _ } = * self ;
407+ let mut needs_to_be_read = false ;
408+ for pat in pats {
409+ return_if_err ! ( mc. cat_pattern( discr_place. clone( ) , pat, |place, pat| {
410+ match & pat. kind {
411+ PatKind :: Binding ( .., opt_sub_pat) => {
412+ // If the opt_sub_pat is None, than the binding does not count as
413+ // a wildcard for the purpose of borrowing discr.
414+ if opt_sub_pat. is_none( ) {
415+ needs_to_be_read = true ;
416+ }
417+ }
418+ PatKind :: Path ( qpath) => {
419+ // A `Path` pattern is just a name like `Foo`. This is either a
420+ // named constant or else it refers to an ADT variant
421+
422+ let res = self . mc. typeck_results. qpath_res( qpath, pat. hir_id) ;
423+ match res {
424+ Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
425+ // Named constants have to be equated with the value
426+ // being matched, so that's a read of the value being matched.
427+ //
428+ // FIXME: We don't actually reads for ZSTs.
429+ needs_to_be_read = true ;
430+ }
431+ _ => {
432+ // Otherwise, this is a struct/enum variant, and so it's
433+ // only a read if we need to read the discriminant.
434+ needs_to_be_read |= is_multivariant_adt( place. place. ty( ) ) ;
435+ }
436+ }
437+ }
438+ PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
439+ // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
440+ // against a multivariant enum or struct. In that case, we have to read
441+ // the discriminant. Otherwise this kind of pattern doesn't actually
442+ // read anything (we'll get invoked for the `...`, which may indeed
443+ // perform some reads).
444+
445+ let place_ty = place. place. ty( ) ;
446+ needs_to_be_read |= is_multivariant_adt( place_ty) ;
447+ }
448+ PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
449+ // If the PatKind is a Lit or a Range then we want
450+ // to borrow discr.
451+ needs_to_be_read = true ;
452+ }
453+ PatKind :: Or ( _)
454+ | PatKind :: Box ( _)
455+ | PatKind :: Slice ( ..)
456+ | PatKind :: Ref ( ..)
457+ | PatKind :: Wild => {
458+ // If the PatKind is Or, Box, Slice or Ref, the decision is made later
459+ // as these patterns contains subpatterns
460+ // If the PatKind is Wild, the decision is made based on the other patterns being
461+ // examined
462+ }
463+ }
464+ } ) ) ;
465+ }
466+
467+ if needs_to_be_read {
468+ self . borrow_expr ( discr, ty:: ImmBorrow ) ;
469+ } else {
470+ let closure_def_id = match discr_place. place . base {
471+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id . to_def_id ( ) ) ,
472+ _ => None ,
473+ } ;
474+
475+ self . delegate . fake_read (
476+ & discr_place,
477+ FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
478+ discr_place. hir_id ,
479+ ) ;
480+
481+ // We always want to walk the discriminant. We want to make sure, for instance,
482+ // that the discriminant has been initialized.
483+ self . walk_expr ( discr) ;
484+ }
485+ }
486+
473487 fn walk_local < F > (
474488 & mut self ,
475489 expr : & hir:: Expr < ' _ > ,
@@ -484,10 +498,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
484498 f ( self ) ;
485499 if let Some ( els) = els {
486500 // borrowing because we need to test the descriminant
487- self . borrow_expr ( expr, ImmBorrow ) ;
501+ // self.borrow_expr(expr, ImmBorrow);
502+ self . maybe_read_scrutinee ( expr, expr_place, from_ref ( pat) . iter ( ) ) ;
488503 self . walk_block ( els)
504+ } else {
505+ self . walk_irrefutable_pat ( & expr_place, & pat) ;
489506 }
490- self . walk_irrefutable_pat ( & expr_place, & pat) ;
491507 }
492508
493509 /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
0 commit comments